Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.view.cts;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertFalse;
     21 import static org.junit.Assert.assertNotNull;
     22 import static org.junit.Assert.assertNotSame;
     23 import static org.junit.Assert.assertNull;
     24 import static org.junit.Assert.assertSame;
     25 import static org.junit.Assert.assertTrue;
     26 import static org.junit.Assert.fail;
     27 import static org.mockito.Matchers.anyInt;
     28 import static org.mockito.Matchers.eq;
     29 import static org.mockito.Mockito.any;
     30 import static org.mockito.Mockito.doAnswer;
     31 import static org.mockito.Mockito.doReturn;
     32 import static org.mockito.Mockito.mock;
     33 import static org.mockito.Mockito.never;
     34 import static org.mockito.Mockito.reset;
     35 import static org.mockito.Mockito.spy;
     36 import static org.mockito.Mockito.times;
     37 import static org.mockito.Mockito.verify;
     38 import static org.mockito.Mockito.verifyZeroInteractions;
     39 import static org.mockito.Mockito.when;
     40 
     41 import android.app.Instrumentation;
     42 import android.content.ClipData;
     43 import android.content.Context;
     44 import android.content.res.ColorStateList;
     45 import android.content.res.Resources;
     46 import android.content.res.XmlResourceParser;
     47 import android.graphics.Bitmap;
     48 import android.graphics.BitmapFactory;
     49 import android.graphics.Canvas;
     50 import android.graphics.Color;
     51 import android.graphics.ColorFilter;
     52 import android.graphics.Point;
     53 import android.graphics.PorterDuff;
     54 import android.graphics.Rect;
     55 import android.graphics.drawable.BitmapDrawable;
     56 import android.graphics.drawable.ColorDrawable;
     57 import android.graphics.drawable.Drawable;
     58 import android.graphics.drawable.StateListDrawable;
     59 import android.hardware.display.DisplayManager;
     60 import android.os.Bundle;
     61 import android.os.Parcelable;
     62 import android.os.SystemClock;
     63 import android.os.Vibrator;
     64 import android.support.test.InstrumentationRegistry;
     65 import android.support.test.annotation.UiThreadTest;
     66 import android.support.test.filters.MediumTest;
     67 import android.support.test.rule.ActivityTestRule;
     68 import android.support.test.runner.AndroidJUnit4;
     69 import android.text.format.DateUtils;
     70 import android.util.AttributeSet;
     71 import android.util.Log;
     72 import android.util.Pair;
     73 import android.util.SparseArray;
     74 import android.util.Xml;
     75 import android.view.ActionMode;
     76 import android.view.ContextMenu;
     77 import android.view.Display;
     78 import android.view.HapticFeedbackConstants;
     79 import android.view.InputDevice;
     80 import android.view.KeyEvent;
     81 import android.view.LayoutInflater;
     82 import android.view.Menu;
     83 import android.view.MenuInflater;
     84 import android.view.MotionEvent;
     85 import android.view.PointerIcon;
     86 import android.view.SoundEffectConstants;
     87 import android.view.TouchDelegate;
     88 import android.view.View;
     89 import android.view.View.BaseSavedState;
     90 import android.view.View.OnLongClickListener;
     91 import android.view.View.OnUnhandledKeyEventListener;
     92 import android.view.ViewConfiguration;
     93 import android.view.ViewGroup;
     94 import android.view.ViewParent;
     95 import android.view.ViewTreeObserver;
     96 import android.view.accessibility.AccessibilityEvent;
     97 import android.view.animation.AlphaAnimation;
     98 import android.view.animation.Animation;
     99 import android.view.inputmethod.EditorInfo;
    100 import android.view.inputmethod.InputConnection;
    101 import android.view.inputmethod.InputMethodManager;
    102 import android.widget.Button;
    103 import android.widget.EditText;
    104 import android.widget.LinearLayout;
    105 import android.widget.TextView;
    106 
    107 import com.android.compatibility.common.util.CtsMouseUtil;
    108 import com.android.compatibility.common.util.CtsTouchUtils;
    109 import com.android.compatibility.common.util.PollingCheck;
    110 
    111 import org.junit.Before;
    112 import org.junit.Rule;
    113 import org.junit.Test;
    114 import org.junit.runner.RunWith;
    115 import org.mockito.ArgumentCaptor;
    116 
    117 import java.lang.reflect.Constructor;
    118 import java.util.ArrayList;
    119 import java.util.Arrays;
    120 import java.util.Collections;
    121 import java.util.concurrent.CountDownLatch;
    122 import java.util.concurrent.TimeUnit;
    123 import java.util.concurrent.atomic.AtomicBoolean;
    124 
    125 /**
    126  * Test {@link View}.
    127  */
    128 @MediumTest
    129 @RunWith(AndroidJUnit4.class)
    130 public class ViewTest {
    131     /** timeout delta when wait in case the system is sluggish */
    132     private static final long TIMEOUT_DELTA = 10000;
    133 
    134     private static final String LOG_TAG = "ViewTest";
    135 
    136     private Instrumentation mInstrumentation;
    137     private ViewTestCtsActivity mActivity;
    138     private Resources mResources;
    139     private MockViewParent mMockParent;
    140     private Context mContext;
    141 
    142     @Rule
    143     public ActivityTestRule<ViewTestCtsActivity> mActivityRule =
    144             new ActivityTestRule<>(ViewTestCtsActivity.class);
    145 
    146     @Rule
    147     public ActivityTestRule<CtsActivity> mCtsActivityRule =
    148             new ActivityTestRule<>(CtsActivity.class, false, false);
    149 
    150     @Before
    151     public void setup() {
    152         mInstrumentation = InstrumentationRegistry.getInstrumentation();
    153         mContext = mInstrumentation.getTargetContext();
    154         mActivity = mActivityRule.getActivity();
    155         PollingCheck.waitFor(mActivity::hasWindowFocus);
    156         mResources = mActivity.getResources();
    157         mMockParent = new MockViewParent(mActivity);
    158         PollingCheck.waitFor(5 * DateUtils.SECOND_IN_MILLIS, mActivity::hasWindowFocus);
    159         assertTrue(mActivity.hasWindowFocus());
    160     }
    161 
    162     @Test
    163     public void testConstructor() {
    164         new View(mActivity);
    165 
    166         final XmlResourceParser parser = mResources.getLayout(R.layout.view_layout);
    167         final AttributeSet attrs = Xml.asAttributeSet(parser);
    168         new View(mActivity, attrs);
    169 
    170         new View(mActivity, null);
    171 
    172         new View(mActivity, attrs, 0);
    173 
    174         new View(mActivity, null, 1);
    175     }
    176 
    177     @Test(expected=NullPointerException.class)
    178     public void testConstructorNullContext1() {
    179         final XmlResourceParser parser = mResources.getLayout(R.layout.view_layout);
    180         final AttributeSet attrs = Xml.asAttributeSet(parser);
    181         new View(null, attrs);
    182     }
    183 
    184     @Test(expected=NullPointerException.class)
    185     public void testConstructorNullContext2() {
    186         new View(null, null, 1);
    187     }
    188 
    189     // Test that validates that Views can be constructed on a thread that
    190     // does not have a Looper. Necessary for async inflation
    191     private Pair<Class<?>, Throwable> sCtorException = null;
    192 
    193     @Test
    194     public void testConstructor2() throws Exception {
    195         final Object[] args = new Object[] { mActivity, null };
    196         final CountDownLatch latch = new CountDownLatch(1);
    197         sCtorException = null;
    198         new Thread() {
    199             @Override
    200             public void run() {
    201                 final Class<?>[] ctorSignature = new Class[] {
    202                         Context.class, AttributeSet.class};
    203                 for (Class<?> clazz : ASYNC_INFLATE_VIEWS) {
    204                     try {
    205                         Constructor<?> constructor = clazz.getConstructor(ctorSignature);
    206                         constructor.setAccessible(true);
    207                         constructor.newInstance(args);
    208                     } catch (Throwable t) {
    209                         sCtorException = new Pair<>(clazz, t);
    210                         break;
    211                     }
    212                 }
    213                 latch.countDown();
    214             }
    215         }.start();
    216         latch.await();
    217         if (sCtorException != null) {
    218             throw new AssertionError("Failed to inflate "
    219                     + sCtorException.first.getName(), sCtorException.second);
    220         }
    221     }
    222 
    223     @Test
    224     public void testGetContext() {
    225         View view = new View(mActivity);
    226         assertSame(mActivity, view.getContext());
    227     }
    228 
    229     @Test
    230     public void testGetResources() {
    231         View view = new View(mActivity);
    232         assertSame(mResources, view.getResources());
    233     }
    234 
    235     @Test
    236     public void testGetAnimation() {
    237         Animation animation = new AlphaAnimation(0.0f, 1.0f);
    238         View view = new View(mActivity);
    239         assertNull(view.getAnimation());
    240 
    241         view.setAnimation(animation);
    242         assertSame(animation, view.getAnimation());
    243 
    244         view.clearAnimation();
    245         assertNull(view.getAnimation());
    246     }
    247 
    248     @Test
    249     public void testSetAnimation() {
    250         Animation animation = new AlphaAnimation(0.0f, 1.0f);
    251         View view = new View(mActivity);
    252         assertNull(view.getAnimation());
    253 
    254         animation.initialize(100, 100, 100, 100);
    255         assertTrue(animation.isInitialized());
    256         view.setAnimation(animation);
    257         assertSame(animation, view.getAnimation());
    258         assertFalse(animation.isInitialized());
    259 
    260         view.setAnimation(null);
    261         assertNull(view.getAnimation());
    262     }
    263 
    264     @Test
    265     public void testClearAnimation() {
    266         Animation animation = new AlphaAnimation(0.0f, 1.0f);
    267         View view = new View(mActivity);
    268 
    269         assertNull(view.getAnimation());
    270         view.clearAnimation();
    271         assertNull(view.getAnimation());
    272 
    273         view.setAnimation(animation);
    274         assertNotNull(view.getAnimation());
    275         view.clearAnimation();
    276         assertNull(view.getAnimation());
    277     }
    278 
    279     @Test(expected=NullPointerException.class)
    280     public void testStartAnimationNull() {
    281         View view = new View(mActivity);
    282         view.startAnimation(null);
    283     }
    284 
    285     @Test
    286     public void testStartAnimation() {
    287         Animation animation = new AlphaAnimation(0.0f, 1.0f);
    288         View view = new View(mActivity);
    289 
    290         animation.setStartTime(1L);
    291         assertEquals(1L, animation.getStartTime());
    292         view.startAnimation(animation);
    293         assertEquals(Animation.START_ON_FIRST_FRAME, animation.getStartTime());
    294     }
    295 
    296     @Test
    297     public void testOnAnimation() throws Throwable {
    298         final Animation animation = new AlphaAnimation(0.0f, 1.0f);
    299         long duration = 2000L;
    300         animation.setDuration(duration);
    301         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
    302 
    303         // check whether it has started
    304         mActivityRule.runOnUiThread(() -> view.startAnimation(animation));
    305         mInstrumentation.waitForIdleSync();
    306 
    307         PollingCheck.waitFor(view::hasCalledOnAnimationStart);
    308 
    309         // check whether it has ended after duration, and alpha changed during this time.
    310         PollingCheck.waitFor(duration + TIMEOUT_DELTA,
    311                 () -> view.hasCalledOnSetAlpha() && view.hasCalledOnAnimationEnd());
    312     }
    313 
    314     @Test
    315     public void testGetParent() {
    316         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
    317         ViewGroup parent = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
    318         assertSame(parent, view.getParent());
    319     }
    320 
    321     @Test
    322     public void testAccessScrollIndicators() {
    323         View view = mActivity.findViewById(R.id.viewlayout_root);
    324 
    325         assertEquals(View.SCROLL_INDICATOR_LEFT | View.SCROLL_INDICATOR_RIGHT,
    326                 view.getScrollIndicators());
    327     }
    328 
    329     @Test
    330     public void testSetScrollIndicators() {
    331         View view = new View(mActivity);
    332 
    333         view.setScrollIndicators(0);
    334         assertEquals(0, view.getScrollIndicators());
    335 
    336         view.setScrollIndicators(View.SCROLL_INDICATOR_LEFT | View.SCROLL_INDICATOR_RIGHT);
    337         assertEquals(View.SCROLL_INDICATOR_LEFT | View.SCROLL_INDICATOR_RIGHT,
    338                 view.getScrollIndicators());
    339 
    340         view.setScrollIndicators(View.SCROLL_INDICATOR_TOP, View.SCROLL_INDICATOR_TOP);
    341         assertEquals(View.SCROLL_INDICATOR_LEFT | View.SCROLL_INDICATOR_RIGHT
    342                         | View.SCROLL_INDICATOR_TOP, view.getScrollIndicators());
    343 
    344         view.setScrollIndicators(0, view.getScrollIndicators());
    345         assertEquals(0, view.getScrollIndicators());
    346     }
    347 
    348     @Test
    349     public void testFindViewById() {
    350         // verify view can find self
    351         View parent = mActivity.findViewById(R.id.viewlayout_root);
    352         assertSame(parent, parent.findViewById(R.id.viewlayout_root));
    353 
    354         // find expected view type
    355         View view = parent.findViewById(R.id.mock_view);
    356         assertTrue(view instanceof MockView);
    357     }
    358 
    359     @Test
    360     public void testRequireViewById() {
    361         View parent = mActivity.findViewById(R.id.viewlayout_root);
    362 
    363         View requiredView = parent.requireViewById(R.id.mock_view);
    364         View foundView = parent.findViewById(R.id.mock_view);
    365         assertSame(foundView, requiredView);
    366         assertTrue(requiredView instanceof MockView);
    367     }
    368 
    369     @Test(expected = IllegalArgumentException.class)
    370     public void testRequireViewByIdNoId() {
    371         View parent = mActivity.findViewById(R.id.viewlayout_root);
    372         parent.requireViewById(View.NO_ID);
    373     }
    374 
    375 
    376     @Test(expected = IllegalArgumentException.class)
    377     public void testRequireViewByIdInvalid() {
    378         View parent = mActivity.findViewById(R.id.viewlayout_root);
    379         parent.requireViewById(0);
    380     }
    381 
    382     @Test(expected = IllegalArgumentException.class)
    383     public void testRequireViewByIdNotFound() {
    384         View parent = mActivity.findViewById(R.id.viewlayout_root);
    385         parent.requireViewById(R.id.view); // id not present in view_layout
    386     }
    387 
    388     @Test
    389     public void testAccessTouchDelegate() throws Throwable {
    390         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
    391         Rect rect = new Rect();
    392         final Button button = new Button(mActivity);
    393         final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT;
    394         final int btnHeight = view.getHeight()/3;
    395         mActivityRule.runOnUiThread(() -> mActivity.addContentView(button,
    396                 new LinearLayout.LayoutParams(WRAP_CONTENT, btnHeight)));
    397         mInstrumentation.waitForIdleSync();
    398         button.getHitRect(rect);
    399         TouchDelegate delegate = spy(new TouchDelegate(rect, button));
    400 
    401         assertNull(view.getTouchDelegate());
    402 
    403         view.setTouchDelegate(delegate);
    404         assertSame(delegate, view.getTouchDelegate());
    405         verify(delegate, never()).onTouchEvent(any());
    406         CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, view);
    407         assertTrue(view.hasCalledOnTouchEvent());
    408         verify(delegate, times(1)).onTouchEvent(any());
    409 
    410         view.setTouchDelegate(null);
    411         assertNull(view.getTouchDelegate());
    412     }
    413 
    414     @Test
    415     public void testMouseEventCallsGetPointerIcon() {
    416         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
    417 
    418         final int[] xy = new int[2];
    419         view.getLocationOnScreen(xy);
    420         final int viewWidth = view.getWidth();
    421         final int viewHeight = view.getHeight();
    422         float x = xy[0] + viewWidth / 2.0f;
    423         float y = xy[1] + viewHeight / 2.0f;
    424 
    425         long eventTime = SystemClock.uptimeMillis();
    426 
    427         MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[1];
    428         pointerCoords[0] = new MotionEvent.PointerCoords();
    429         pointerCoords[0].x = x;
    430         pointerCoords[0].y = y;
    431 
    432         final int[] pointerIds = new int[1];
    433         pointerIds[0] = 0;
    434 
    435         MotionEvent event = MotionEvent.obtain(0, eventTime, MotionEvent.ACTION_HOVER_MOVE,
    436                 1, pointerIds, pointerCoords, 0, 0, 0, 0, 0, InputDevice.SOURCE_MOUSE, 0);
    437         mInstrumentation.sendPointerSync(event);
    438         mInstrumentation.waitForIdleSync();
    439 
    440         assertTrue(view.hasCalledOnResolvePointerIcon());
    441 
    442         final MockView view2 = (MockView) mActivity.findViewById(R.id.scroll_view);
    443         assertFalse(view2.hasCalledOnResolvePointerIcon());
    444     }
    445 
    446     @Test
    447     public void testAccessPointerIcon() {
    448         View view = mActivity.findViewById(R.id.pointer_icon_layout);
    449         MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
    450 
    451         // First view has pointerIcon="help"
    452         assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HELP),
    453                      view.onResolvePointerIcon(event, 0));
    454 
    455         // Second view inherits pointerIcon="crosshair" from the parent
    456         event.setLocation(0, 21);
    457         assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_CROSSHAIR),
    458                      view.onResolvePointerIcon(event, 0));
    459 
    460         // Third view has custom pointer icon defined in a resource.
    461         event.setLocation(0, 41);
    462         assertNotNull(view.onResolvePointerIcon(event, 0));
    463 
    464         // Parent view has pointerIcon="crosshair"
    465         event.setLocation(0, 61);
    466         assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_CROSSHAIR),
    467                      view.onResolvePointerIcon(event, 0));
    468 
    469         // Outside of the parent view, no pointer icon defined.
    470         event.setLocation(0, 71);
    471         assertNull(view.onResolvePointerIcon(event, 0));
    472 
    473         view.setPointerIcon(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_TEXT));
    474         assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_TEXT),
    475                      view.onResolvePointerIcon(event, 0));
    476         event.recycle();
    477     }
    478 
    479     @Test
    480     public void testPointerIconOverlap() throws Throwable {
    481         View parent = mActivity.findViewById(R.id.pointer_icon_overlap);
    482         View child1 = mActivity.findViewById(R.id.pointer_icon_overlap_child1);
    483         View child2 = mActivity.findViewById(R.id.pointer_icon_overlap_child2);
    484         View child3 = mActivity.findViewById(R.id.pointer_icon_overlap_child3);
    485 
    486         PointerIcon iconParent = PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HAND);
    487         PointerIcon iconChild1 = PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HELP);
    488         PointerIcon iconChild2 = PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_TEXT);
    489         PointerIcon iconChild3 = PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_GRAB);
    490 
    491         parent.setPointerIcon(iconParent);
    492         child1.setPointerIcon(iconChild1);
    493         child2.setPointerIcon(iconChild2);
    494         child3.setPointerIcon(iconChild3);
    495 
    496         MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
    497 
    498         assertEquals(iconChild3, parent.onResolvePointerIcon(event, 0));
    499 
    500         setVisibilityOnUiThread(child3, View.GONE);
    501         assertEquals(iconChild2, parent.onResolvePointerIcon(event, 0));
    502 
    503         child2.setPointerIcon(null);
    504         assertEquals(iconChild1, parent.onResolvePointerIcon(event, 0));
    505 
    506         setVisibilityOnUiThread(child1, View.GONE);
    507         assertEquals(iconParent, parent.onResolvePointerIcon(event, 0));
    508 
    509         event.recycle();
    510     }
    511 
    512     @Test
    513     public void testCreatePointerIcons() {
    514         assertSystemPointerIcon(PointerIcon.TYPE_NULL);
    515         assertSystemPointerIcon(PointerIcon.TYPE_DEFAULT);
    516         assertSystemPointerIcon(PointerIcon.TYPE_ARROW);
    517         assertSystemPointerIcon(PointerIcon.TYPE_CONTEXT_MENU);
    518         assertSystemPointerIcon(PointerIcon.TYPE_HAND);
    519         assertSystemPointerIcon(PointerIcon.TYPE_HELP);
    520         assertSystemPointerIcon(PointerIcon.TYPE_WAIT);
    521         assertSystemPointerIcon(PointerIcon.TYPE_CELL);
    522         assertSystemPointerIcon(PointerIcon.TYPE_CROSSHAIR);
    523         assertSystemPointerIcon(PointerIcon.TYPE_TEXT);
    524         assertSystemPointerIcon(PointerIcon.TYPE_VERTICAL_TEXT);
    525         assertSystemPointerIcon(PointerIcon.TYPE_ALIAS);
    526         assertSystemPointerIcon(PointerIcon.TYPE_COPY);
    527         assertSystemPointerIcon(PointerIcon.TYPE_NO_DROP);
    528         assertSystemPointerIcon(PointerIcon.TYPE_ALL_SCROLL);
    529         assertSystemPointerIcon(PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW);
    530         assertSystemPointerIcon(PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW);
    531         assertSystemPointerIcon(PointerIcon.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW);
    532         assertSystemPointerIcon(PointerIcon.TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW);
    533         assertSystemPointerIcon(PointerIcon.TYPE_ZOOM_IN);
    534         assertSystemPointerIcon(PointerIcon.TYPE_ZOOM_OUT);
    535         assertSystemPointerIcon(PointerIcon.TYPE_GRAB);
    536 
    537         assertNotNull(PointerIcon.load(mResources, R.drawable.custom_pointer_icon));
    538 
    539         Bitmap bitmap = BitmapFactory.decodeResource(mResources, R.drawable.icon_blue);
    540         assertNotNull(PointerIcon.create(bitmap, 0, 0));
    541         assertNotNull(PointerIcon.create(bitmap, bitmap.getWidth() / 2, bitmap.getHeight() / 2));
    542 
    543         try {
    544             PointerIcon.create(bitmap, -1, 0);
    545             fail("Hotspot x can not be < 0");
    546         } catch (IllegalArgumentException ignore) {
    547         }
    548 
    549         try {
    550             PointerIcon.create(bitmap, 0, -1);
    551             fail("Hotspot y can not be < 0");
    552         } catch (IllegalArgumentException ignore) {
    553         }
    554 
    555         try {
    556             PointerIcon.create(bitmap, bitmap.getWidth(), 0);
    557             fail("Hotspot x cannot be >= width");
    558         } catch (IllegalArgumentException ignore) {
    559         }
    560 
    561         try {
    562             PointerIcon.create(bitmap, 0, bitmap.getHeight());
    563             fail("Hotspot x cannot be >= height");
    564         } catch (IllegalArgumentException e) {
    565         }
    566     }
    567 
    568     private void assertSystemPointerIcon(int style) {
    569         assertNotNull(PointerIcon.getSystemIcon(mActivity, style));
    570     }
    571 
    572     @UiThreadTest
    573     @Test
    574     public void testAccessTag() {
    575         ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
    576         MockView mockView = (MockView) mActivity.findViewById(R.id.mock_view);
    577         MockView scrollView = (MockView) mActivity.findViewById(R.id.scroll_view);
    578 
    579         ViewData viewData = new ViewData();
    580         viewData.childCount = 3;
    581         viewData.tag = "linearLayout";
    582         viewData.firstChild = mockView;
    583         viewGroup.setTag(viewData);
    584         viewGroup.setFocusable(true);
    585         assertSame(viewData, viewGroup.getTag());
    586 
    587         final String tag = "mock";
    588         assertNull(mockView.getTag());
    589         mockView.setTag(tag);
    590         assertEquals(tag, mockView.getTag());
    591 
    592         scrollView.setTag(viewGroup);
    593         assertSame(viewGroup, scrollView.getTag());
    594 
    595         assertSame(viewGroup, viewGroup.findViewWithTag(viewData));
    596         assertSame(mockView, viewGroup.findViewWithTag(tag));
    597         assertSame(scrollView, viewGroup.findViewWithTag(viewGroup));
    598 
    599         mockView.setTag(null);
    600         assertNull(mockView.getTag());
    601     }
    602 
    603     @Test
    604     public void testOnSizeChanged() throws Throwable {
    605         final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
    606         final MockView mockView = new MockView(mActivity);
    607         assertEquals(-1, mockView.getOldWOnSizeChanged());
    608         assertEquals(-1, mockView.getOldHOnSizeChanged());
    609         mActivityRule.runOnUiThread(() -> viewGroup.addView(mockView));
    610         mInstrumentation.waitForIdleSync();
    611         assertTrue(mockView.hasCalledOnSizeChanged());
    612         assertEquals(0, mockView.getOldWOnSizeChanged());
    613         assertEquals(0, mockView.getOldHOnSizeChanged());
    614 
    615         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
    616         assertTrue(view.hasCalledOnSizeChanged());
    617         view.reset();
    618         assertEquals(-1, view.getOldWOnSizeChanged());
    619         assertEquals(-1, view.getOldHOnSizeChanged());
    620         int oldw = view.getWidth();
    621         int oldh = view.getHeight();
    622         final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(200, 100);
    623         mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams));
    624         mInstrumentation.waitForIdleSync();
    625         assertTrue(view.hasCalledOnSizeChanged());
    626         assertEquals(oldw, view.getOldWOnSizeChanged());
    627         assertEquals(oldh, view.getOldHOnSizeChanged());
    628     }
    629 
    630 
    631     @Test(expected=NullPointerException.class)
    632     public void testGetHitRectNull() {
    633         MockView view = new MockView(mActivity);
    634         view.getHitRect(null);
    635     }
    636 
    637     @Test
    638     public void testGetHitRect() {
    639         Rect outRect = new Rect();
    640         View mockView = mActivity.findViewById(R.id.mock_view);
    641         mockView.getHitRect(outRect);
    642         assertEquals(0, outRect.left);
    643         assertEquals(0, outRect.top);
    644         assertEquals(mockView.getWidth(), outRect.right);
    645         assertEquals(mockView.getHeight(), outRect.bottom);
    646     }
    647 
    648     @Test
    649     public void testForceLayout() {
    650         View view = new View(mActivity);
    651 
    652         assertFalse(view.isLayoutRequested());
    653         view.forceLayout();
    654         assertTrue(view.isLayoutRequested());
    655 
    656         view.forceLayout();
    657         assertTrue(view.isLayoutRequested());
    658     }
    659 
    660     @Test
    661     public void testIsLayoutRequested() {
    662         View view = new View(mActivity);
    663 
    664         assertFalse(view.isLayoutRequested());
    665         view.forceLayout();
    666         assertTrue(view.isLayoutRequested());
    667 
    668         view.layout(0, 0, 0, 0);
    669         assertFalse(view.isLayoutRequested());
    670     }
    671 
    672     @Test
    673     public void testRequestLayout() {
    674         MockView view = new MockView(mActivity);
    675         assertFalse(view.isLayoutRequested());
    676         assertNull(view.getParent());
    677 
    678         view.requestLayout();
    679         assertTrue(view.isLayoutRequested());
    680 
    681         view.setParent(mMockParent);
    682         assertTrue(mMockParent.hasRequestLayout());
    683 
    684         mMockParent.reset();
    685         view.requestLayout();
    686         assertTrue(view.isLayoutRequested());
    687         assertTrue(mMockParent.hasRequestLayout());
    688     }
    689 
    690     @Test
    691     public void testLayout() throws Throwable {
    692         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
    693         assertTrue(view.hasCalledOnLayout());
    694 
    695         view.reset();
    696         assertFalse(view.hasCalledOnLayout());
    697         mActivityRule.runOnUiThread(view::requestLayout);
    698         mInstrumentation.waitForIdleSync();
    699         assertTrue(view.hasCalledOnLayout());
    700     }
    701 
    702     @Test
    703     public void testGetBaseline() {
    704         View view = new View(mActivity);
    705 
    706         assertEquals(-1, view.getBaseline());
    707     }
    708 
    709     @Test
    710     public void testAccessBackground() {
    711         View view = new View(mActivity);
    712         Drawable d1 = mResources.getDrawable(R.drawable.scenery);
    713         Drawable d2 = mResources.getDrawable(R.drawable.pass);
    714 
    715         assertNull(view.getBackground());
    716 
    717         view.setBackgroundDrawable(d1);
    718         assertEquals(d1, view.getBackground());
    719 
    720         view.setBackgroundDrawable(d2);
    721         assertEquals(d2, view.getBackground());
    722 
    723         view.setBackgroundDrawable(null);
    724         assertNull(view.getBackground());
    725     }
    726 
    727     @Test
    728     public void testSetBackgroundResource() {
    729         View view = new View(mActivity);
    730 
    731         assertNull(view.getBackground());
    732 
    733         view.setBackgroundResource(R.drawable.pass);
    734         assertNotNull(view.getBackground());
    735 
    736         view.setBackgroundResource(0);
    737         assertNull(view.getBackground());
    738     }
    739 
    740     @Test
    741     public void testAccessDrawingCacheBackgroundColor() {
    742         View view = new View(mActivity);
    743 
    744         assertEquals(0, view.getDrawingCacheBackgroundColor());
    745 
    746         view.setDrawingCacheBackgroundColor(0xFF00FF00);
    747         assertEquals(0xFF00FF00, view.getDrawingCacheBackgroundColor());
    748 
    749         view.setDrawingCacheBackgroundColor(-1);
    750         assertEquals(-1, view.getDrawingCacheBackgroundColor());
    751     }
    752 
    753     @Test
    754     public void testSetBackgroundColor() {
    755         View view = new View(mActivity);
    756         ColorDrawable colorDrawable;
    757         assertNull(view.getBackground());
    758 
    759         view.setBackgroundColor(0xFFFF0000);
    760         colorDrawable = (ColorDrawable) view.getBackground();
    761         assertNotNull(colorDrawable);
    762         assertEquals(0xFF, colorDrawable.getAlpha());
    763 
    764         view.setBackgroundColor(0);
    765         colorDrawable = (ColorDrawable) view.getBackground();
    766         assertNotNull(colorDrawable);
    767         assertEquals(0, colorDrawable.getAlpha());
    768     }
    769 
    770     @Test
    771     public void testVerifyDrawable() {
    772         MockView view = new MockView(mActivity);
    773         Drawable d1 = mResources.getDrawable(R.drawable.scenery);
    774         Drawable d2 = mResources.getDrawable(R.drawable.pass);
    775 
    776         assertNull(view.getBackground());
    777         assertTrue(view.verifyDrawable(null));
    778         assertFalse(view.verifyDrawable(d1));
    779 
    780         view.setBackgroundDrawable(d1);
    781         assertTrue(view.verifyDrawable(d1));
    782         assertFalse(view.verifyDrawable(d2));
    783     }
    784 
    785     @Test
    786     public void testGetDrawingRect() {
    787         MockView view = new MockView(mActivity);
    788         Rect outRect = new Rect();
    789 
    790         view.getDrawingRect(outRect);
    791         assertEquals(0, outRect.left);
    792         assertEquals(0, outRect.top);
    793         assertEquals(0, outRect.right);
    794         assertEquals(0, outRect.bottom);
    795 
    796         view.scrollTo(10, 100);
    797         view.getDrawingRect(outRect);
    798         assertEquals(10, outRect.left);
    799         assertEquals(100, outRect.top);
    800         assertEquals(10, outRect.right);
    801         assertEquals(100, outRect.bottom);
    802 
    803         View mockView = mActivity.findViewById(R.id.mock_view);
    804         mockView.getDrawingRect(outRect);
    805         assertEquals(0, outRect.left);
    806         assertEquals(0, outRect.top);
    807         assertEquals(mockView.getWidth(), outRect.right);
    808         assertEquals(mockView.getHeight(), outRect.bottom);
    809     }
    810 
    811     @Test
    812     public void testGetFocusedRect() {
    813         MockView view = new MockView(mActivity);
    814         Rect outRect = new Rect();
    815 
    816         view.getFocusedRect(outRect);
    817         assertEquals(0, outRect.left);
    818         assertEquals(0, outRect.top);
    819         assertEquals(0, outRect.right);
    820         assertEquals(0, outRect.bottom);
    821 
    822         view.scrollTo(10, 100);
    823         view.getFocusedRect(outRect);
    824         assertEquals(10, outRect.left);
    825         assertEquals(100, outRect.top);
    826         assertEquals(10, outRect.right);
    827         assertEquals(100, outRect.bottom);
    828     }
    829 
    830     @Test
    831     public void testGetGlobalVisibleRectPoint() throws Throwable {
    832         final View view = mActivity.findViewById(R.id.mock_view);
    833         final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
    834         Rect rect = new Rect();
    835         Point point = new Point();
    836 
    837         assertTrue(view.getGlobalVisibleRect(rect, point));
    838         Rect rcParent = new Rect();
    839         Point ptParent = new Point();
    840         viewGroup.getGlobalVisibleRect(rcParent, ptParent);
    841         assertEquals(rcParent.left, rect.left);
    842         assertEquals(rcParent.top, rect.top);
    843         assertEquals(rect.left + view.getWidth(), rect.right);
    844         assertEquals(rect.top + view.getHeight(), rect.bottom);
    845         assertEquals(ptParent.x, point.x);
    846         assertEquals(ptParent.y, point.y);
    847 
    848         // width is 0
    849         final LinearLayout.LayoutParams layoutParams1 = new LinearLayout.LayoutParams(0, 300);
    850         mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams1));
    851         mInstrumentation.waitForIdleSync();
    852         assertFalse(view.getGlobalVisibleRect(rect, point));
    853 
    854         // height is -10
    855         final LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams(200, -10);
    856         mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams2));
    857         mInstrumentation.waitForIdleSync();
    858         assertFalse(view.getGlobalVisibleRect(rect, point));
    859 
    860         Display display = mActivity.getWindowManager().getDefaultDisplay();
    861         int halfWidth = display.getWidth() / 2;
    862         int halfHeight = display.getHeight() /2;
    863 
    864         final LinearLayout.LayoutParams layoutParams3 =
    865                 new LinearLayout.LayoutParams(halfWidth, halfHeight);
    866         mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams3));
    867         mInstrumentation.waitForIdleSync();
    868         assertTrue(view.getGlobalVisibleRect(rect, point));
    869         assertEquals(rcParent.left, rect.left);
    870         assertEquals(rcParent.top, rect.top);
    871         assertEquals(rect.left + halfWidth, rect.right);
    872         assertEquals(rect.top + halfHeight, rect.bottom);
    873         assertEquals(ptParent.x, point.x);
    874         assertEquals(ptParent.y, point.y);
    875     }
    876 
    877     @Test
    878     public void testGetGlobalVisibleRect() throws Throwable {
    879         final View view = mActivity.findViewById(R.id.mock_view);
    880         final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
    881         Rect rect = new Rect();
    882 
    883         assertTrue(view.getGlobalVisibleRect(rect));
    884         Rect rcParent = new Rect();
    885         viewGroup.getGlobalVisibleRect(rcParent);
    886         assertEquals(rcParent.left, rect.left);
    887         assertEquals(rcParent.top, rect.top);
    888         assertEquals(rect.left + view.getWidth(), rect.right);
    889         assertEquals(rect.top + view.getHeight(), rect.bottom);
    890 
    891         // width is 0
    892         final LinearLayout.LayoutParams layoutParams1 = new LinearLayout.LayoutParams(0, 300);
    893         mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams1));
    894         mInstrumentation.waitForIdleSync();
    895         assertFalse(view.getGlobalVisibleRect(rect));
    896 
    897         // height is -10
    898         final LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams(200, -10);
    899         mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams2));
    900         mInstrumentation.waitForIdleSync();
    901         assertFalse(view.getGlobalVisibleRect(rect));
    902 
    903         Display display = mActivity.getWindowManager().getDefaultDisplay();
    904         int halfWidth = display.getWidth() / 2;
    905         int halfHeight = display.getHeight() /2;
    906 
    907         final LinearLayout.LayoutParams layoutParams3 =
    908                 new LinearLayout.LayoutParams(halfWidth, halfHeight);
    909         mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams3));
    910         mInstrumentation.waitForIdleSync();
    911         assertTrue(view.getGlobalVisibleRect(rect));
    912         assertEquals(rcParent.left, rect.left);
    913         assertEquals(rcParent.top, rect.top);
    914         assertEquals(rect.left + halfWidth, rect.right);
    915         assertEquals(rect.top + halfHeight, rect.bottom);
    916     }
    917 
    918     @Test
    919     public void testComputeHorizontalScroll() throws Throwable {
    920         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
    921 
    922         assertEquals(0, view.computeHorizontalScrollOffset());
    923         assertEquals(view.getWidth(), view.computeHorizontalScrollRange());
    924         assertEquals(view.getWidth(), view.computeHorizontalScrollExtent());
    925 
    926         mActivityRule.runOnUiThread(() -> view.scrollTo(12, 0));
    927         mInstrumentation.waitForIdleSync();
    928         assertEquals(12, view.computeHorizontalScrollOffset());
    929         assertEquals(view.getWidth(), view.computeHorizontalScrollRange());
    930         assertEquals(view.getWidth(), view.computeHorizontalScrollExtent());
    931 
    932         mActivityRule.runOnUiThread(() -> view.scrollBy(12, 0));
    933         mInstrumentation.waitForIdleSync();
    934         assertEquals(24, view.computeHorizontalScrollOffset());
    935         assertEquals(view.getWidth(), view.computeHorizontalScrollRange());
    936         assertEquals(view.getWidth(), view.computeHorizontalScrollExtent());
    937 
    938         int newWidth = 200;
    939         final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(newWidth, 100);
    940         mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams));
    941         mInstrumentation.waitForIdleSync();
    942         assertEquals(24, view.computeHorizontalScrollOffset());
    943         assertEquals(newWidth, view.getWidth());
    944         assertEquals(view.getWidth(), view.computeHorizontalScrollRange());
    945         assertEquals(view.getWidth(), view.computeHorizontalScrollExtent());
    946     }
    947 
    948     @Test
    949     public void testComputeVerticalScroll() throws Throwable {
    950         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
    951 
    952         assertEquals(0, view.computeVerticalScrollOffset());
    953         assertEquals(view.getHeight(), view.computeVerticalScrollRange());
    954         assertEquals(view.getHeight(), view.computeVerticalScrollExtent());
    955 
    956         final int scrollToY = 34;
    957         mActivityRule.runOnUiThread(() -> view.scrollTo(0, scrollToY));
    958         mInstrumentation.waitForIdleSync();
    959         assertEquals(scrollToY, view.computeVerticalScrollOffset());
    960         assertEquals(view.getHeight(), view.computeVerticalScrollRange());
    961         assertEquals(view.getHeight(), view.computeVerticalScrollExtent());
    962 
    963         final int scrollByY = 200;
    964         mActivityRule.runOnUiThread(() -> view.scrollBy(0, scrollByY));
    965         mInstrumentation.waitForIdleSync();
    966         assertEquals(scrollToY + scrollByY, view.computeVerticalScrollOffset());
    967         assertEquals(view.getHeight(), view.computeVerticalScrollRange());
    968         assertEquals(view.getHeight(), view.computeVerticalScrollExtent());
    969 
    970         int newHeight = 333;
    971         final LinearLayout.LayoutParams layoutParams =
    972                 new LinearLayout.LayoutParams(200, newHeight);
    973         mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams));
    974         mInstrumentation.waitForIdleSync();
    975         assertEquals(scrollToY + scrollByY, view.computeVerticalScrollOffset());
    976         assertEquals(newHeight, view.getHeight());
    977         assertEquals(view.getHeight(), view.computeVerticalScrollRange());
    978         assertEquals(view.getHeight(), view.computeVerticalScrollExtent());
    979     }
    980 
    981     @Test
    982     public void testGetFadingEdgeStrength() throws Throwable {
    983         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
    984 
    985         assertEquals(0f, view.getLeftFadingEdgeStrength(), 0.0f);
    986         assertEquals(0f, view.getRightFadingEdgeStrength(), 0.0f);
    987         assertEquals(0f, view.getTopFadingEdgeStrength(), 0.0f);
    988         assertEquals(0f, view.getBottomFadingEdgeStrength(), 0.0f);
    989 
    990         mActivityRule.runOnUiThread(() -> view.scrollTo(10, 10));
    991         mInstrumentation.waitForIdleSync();
    992         assertEquals(1f, view.getLeftFadingEdgeStrength(), 0.0f);
    993         assertEquals(0f, view.getRightFadingEdgeStrength(), 0.0f);
    994         assertEquals(1f, view.getTopFadingEdgeStrength(), 0.0f);
    995         assertEquals(0f, view.getBottomFadingEdgeStrength(), 0.0f);
    996 
    997         mActivityRule.runOnUiThread(() -> view.scrollTo(-10, -10));
    998         mInstrumentation.waitForIdleSync();
    999         assertEquals(0f, view.getLeftFadingEdgeStrength(), 0.0f);
   1000         assertEquals(1f, view.getRightFadingEdgeStrength(), 0.0f);
   1001         assertEquals(0f, view.getTopFadingEdgeStrength(), 0.0f);
   1002         assertEquals(1f, view.getBottomFadingEdgeStrength(), 0.0f);
   1003     }
   1004 
   1005     @Test
   1006     public void testGetLeftFadingEdgeStrength() {
   1007         MockView view = new MockView(mActivity);
   1008 
   1009         assertEquals(0.0f, view.getLeftFadingEdgeStrength(), 0.0f);
   1010 
   1011         view.scrollTo(1, 0);
   1012         assertEquals(1.0f, view.getLeftFadingEdgeStrength(), 0.0f);
   1013     }
   1014 
   1015     @Test
   1016     public void testGetRightFadingEdgeStrength() {
   1017         MockView view = new MockView(mActivity);
   1018 
   1019         assertEquals(0.0f, view.getRightFadingEdgeStrength(), 0.0f);
   1020 
   1021         view.scrollTo(-1, 0);
   1022         assertEquals(1.0f, view.getRightFadingEdgeStrength(), 0.0f);
   1023     }
   1024 
   1025     @Test
   1026     public void testGetBottomFadingEdgeStrength() {
   1027         MockView view = new MockView(mActivity);
   1028 
   1029         assertEquals(0.0f, view.getBottomFadingEdgeStrength(), 0.0f);
   1030 
   1031         view.scrollTo(0, -2);
   1032         assertEquals(1.0f, view.getBottomFadingEdgeStrength(), 0.0f);
   1033     }
   1034 
   1035     @Test
   1036     public void testGetTopFadingEdgeStrength() {
   1037         MockView view = new MockView(mActivity);
   1038 
   1039         assertEquals(0.0f, view.getTopFadingEdgeStrength(), 0.0f);
   1040 
   1041         view.scrollTo(0, 2);
   1042         assertEquals(1.0f, view.getTopFadingEdgeStrength(), 0.0f);
   1043     }
   1044 
   1045     @Test
   1046     public void testResolveSize() {
   1047         assertEquals(50, View.resolveSize(50, View.MeasureSpec.UNSPECIFIED));
   1048 
   1049         assertEquals(40, View.resolveSize(50, 40 | View.MeasureSpec.EXACTLY));
   1050 
   1051         assertEquals(30, View.resolveSize(50, 30 | View.MeasureSpec.AT_MOST));
   1052 
   1053         assertEquals(20, View.resolveSize(20, 30 | View.MeasureSpec.AT_MOST));
   1054     }
   1055 
   1056     @Test
   1057     public void testGetDefaultSize() {
   1058         assertEquals(50, View.getDefaultSize(50, View.MeasureSpec.UNSPECIFIED));
   1059 
   1060         assertEquals(40, View.getDefaultSize(50, 40 | View.MeasureSpec.EXACTLY));
   1061 
   1062         assertEquals(30, View.getDefaultSize(50, 30 | View.MeasureSpec.AT_MOST));
   1063 
   1064         assertEquals(30, View.getDefaultSize(20, 30 | View.MeasureSpec.AT_MOST));
   1065     }
   1066 
   1067     @Test
   1068     public void testAccessId() {
   1069         View view = new View(mActivity);
   1070 
   1071         assertEquals(View.NO_ID, view.getId());
   1072 
   1073         view.setId(10);
   1074         assertEquals(10, view.getId());
   1075 
   1076         view.setId(0xFFFFFFFF);
   1077         assertEquals(0xFFFFFFFF, view.getId());
   1078     }
   1079 
   1080     @Test
   1081     public void testAccessLongClickable() {
   1082         View view = new View(mActivity);
   1083 
   1084         assertFalse(view.isLongClickable());
   1085 
   1086         view.setLongClickable(true);
   1087         assertTrue(view.isLongClickable());
   1088 
   1089         view.setLongClickable(false);
   1090         assertFalse(view.isLongClickable());
   1091     }
   1092 
   1093     @Test
   1094     public void testAccessClickable() {
   1095         View view = new View(mActivity);
   1096 
   1097         assertFalse(view.isClickable());
   1098 
   1099         view.setClickable(true);
   1100         assertTrue(view.isClickable());
   1101 
   1102         view.setClickable(false);
   1103         assertFalse(view.isClickable());
   1104     }
   1105 
   1106     @Test
   1107     public void testAccessContextClickable() {
   1108         View view = new View(mActivity);
   1109 
   1110         assertFalse(view.isContextClickable());
   1111 
   1112         view.setContextClickable(true);
   1113         assertTrue(view.isContextClickable());
   1114 
   1115         view.setContextClickable(false);
   1116         assertFalse(view.isContextClickable());
   1117     }
   1118 
   1119     @Test
   1120     public void testGetContextMenuInfo() {
   1121         MockView view = new MockView(mActivity);
   1122 
   1123         assertNull(view.getContextMenuInfo());
   1124     }
   1125 
   1126     @Test
   1127     public void testSetOnCreateContextMenuListener() {
   1128         View view = new View(mActivity);
   1129         assertFalse(view.isLongClickable());
   1130 
   1131         view.setOnCreateContextMenuListener(null);
   1132         assertTrue(view.isLongClickable());
   1133 
   1134         view.setOnCreateContextMenuListener(mock(View.OnCreateContextMenuListener.class));
   1135         assertTrue(view.isLongClickable());
   1136     }
   1137 
   1138     @Test
   1139     public void testCreateContextMenu() throws Throwable {
   1140         mActivityRule.runOnUiThread(() -> {
   1141             View.OnCreateContextMenuListener listener =
   1142                     mock(View.OnCreateContextMenuListener.class);
   1143             MockView view = new MockView(mActivity);
   1144             mActivity.setContentView(view);
   1145             mActivity.registerForContextMenu(view);
   1146             view.setOnCreateContextMenuListener(listener);
   1147             assertFalse(view.hasCalledOnCreateContextMenu());
   1148             verifyZeroInteractions(listener);
   1149 
   1150             view.showContextMenu();
   1151             assertTrue(view.hasCalledOnCreateContextMenu());
   1152             verify(listener, times(1)).onCreateContextMenu(
   1153                     any(), eq(view), any());
   1154         });
   1155     }
   1156 
   1157     @Test(expected=NullPointerException.class)
   1158     public void testCreateContextMenuNull() {
   1159         MockView view = new MockView(mActivity);
   1160         view.createContextMenu(null);
   1161     }
   1162 
   1163     @Test
   1164     public void testAddFocusables() {
   1165         View view = new View(mActivity);
   1166         ArrayList<View> viewList = new ArrayList<>();
   1167 
   1168         // view is not focusable
   1169         assertFalse(view.isFocusable());
   1170         assertEquals(0, viewList.size());
   1171         view.addFocusables(viewList, 0);
   1172         assertEquals(0, viewList.size());
   1173 
   1174         // view is focusable
   1175         view.setFocusable(true);
   1176         view.addFocusables(viewList, 0);
   1177         assertEquals(1, viewList.size());
   1178         assertEquals(view, viewList.get(0));
   1179 
   1180         // null array should be ignored
   1181         view.addFocusables(null, 0);
   1182     }
   1183 
   1184     @Test
   1185     public void testGetFocusables() {
   1186         View view = new View(mActivity);
   1187         ArrayList<View> viewList;
   1188 
   1189         // view is not focusable
   1190         assertFalse(view.isFocusable());
   1191         viewList = view.getFocusables(0);
   1192         assertEquals(0, viewList.size());
   1193 
   1194         // view is focusable
   1195         view.setFocusable(true);
   1196         viewList = view.getFocusables(0);
   1197         assertEquals(1, viewList.size());
   1198         assertEquals(view, viewList.get(0));
   1199 
   1200         viewList = view.getFocusables(-1);
   1201         assertEquals(1, viewList.size());
   1202         assertEquals(view, viewList.get(0));
   1203     }
   1204 
   1205     @Test
   1206     public void testAddFocusablesWithoutTouchMode() {
   1207         View view = new View(mActivity);
   1208         assertFalse("test sanity", view.isInTouchMode());
   1209         focusableInTouchModeTest(view, false);
   1210     }
   1211 
   1212     @Test
   1213     public void testAddFocusablesInTouchMode() {
   1214         View view = spy(new View(mActivity));
   1215         when(view.isInTouchMode()).thenReturn(true);
   1216         focusableInTouchModeTest(view, true);
   1217     }
   1218 
   1219     private void focusableInTouchModeTest(View view, boolean inTouchMode) {
   1220         ArrayList<View> views = new ArrayList<>();
   1221 
   1222         view.setFocusableInTouchMode(false);
   1223         view.setFocusable(true);
   1224 
   1225         view.addFocusables(views, View.FOCUS_FORWARD);
   1226         if (inTouchMode) {
   1227             assertEquals(Collections.emptyList(), views);
   1228         } else {
   1229             assertEquals(Collections.singletonList(view), views);
   1230         }
   1231 
   1232         views.clear();
   1233         view.addFocusables(views, View.FOCUS_FORWARD, View.FOCUSABLES_ALL);
   1234         assertEquals(Collections.singletonList(view), views);
   1235 
   1236         views.clear();
   1237         view.addFocusables(views, View.FOCUS_FORWARD, View.FOCUSABLES_TOUCH_MODE);
   1238         assertEquals(Collections.emptyList(), views);
   1239 
   1240         view.setFocusableInTouchMode(true);
   1241 
   1242         views.clear();
   1243         view.addFocusables(views, View.FOCUS_FORWARD);
   1244         assertEquals(Collections.singletonList(view), views);
   1245 
   1246         views.clear();
   1247         view.addFocusables(views, View.FOCUS_FORWARD, View.FOCUSABLES_ALL);
   1248         assertEquals(Collections.singletonList(view), views);
   1249 
   1250         views.clear();
   1251         view.addFocusables(views, View.FOCUS_FORWARD, View.FOCUSABLES_TOUCH_MODE);
   1252         assertEquals(Collections.singletonList(view), views);
   1253 
   1254         view.setFocusable(false);
   1255 
   1256         views.clear();
   1257         view.addFocusables(views, View.FOCUS_FORWARD);
   1258         assertEquals(Collections.emptyList(), views);
   1259 
   1260         views.clear();
   1261         view.addFocusables(views, View.FOCUS_FORWARD, View.FOCUSABLES_ALL);
   1262         assertEquals(Collections.emptyList(), views);
   1263 
   1264         views.clear();
   1265         view.addFocusables(views, View.FOCUS_FORWARD, View.FOCUSABLES_TOUCH_MODE);
   1266         assertEquals(Collections.emptyList(), views);
   1267     }
   1268 
   1269     @Test
   1270     public void testAddKeyboardNavigationClusters() {
   1271         View view = new View(mActivity);
   1272         ArrayList<View> viewList = new ArrayList<>();
   1273 
   1274         // View is not a keyboard navigation cluster
   1275         assertFalse(view.isKeyboardNavigationCluster());
   1276         view.addKeyboardNavigationClusters(viewList, 0);
   1277         assertEquals(0, viewList.size());
   1278 
   1279         // View is a cluster (but not focusable, so technically empty)
   1280         view.setKeyboardNavigationCluster(true);
   1281         view.addKeyboardNavigationClusters(viewList, 0);
   1282         assertEquals(0, viewList.size());
   1283         viewList.clear();
   1284         // a focusable cluster is not-empty
   1285         view.setFocusableInTouchMode(true);
   1286         view.addKeyboardNavigationClusters(viewList, 0);
   1287         assertEquals(1, viewList.size());
   1288         assertEquals(view, viewList.get(0));
   1289     }
   1290 
   1291     @Test
   1292     public void testKeyboardNavigationClusterSearch() throws Throwable {
   1293         mActivityRule.runOnUiThread(() -> {
   1294             ViewGroup decorView = (ViewGroup) mActivity.getWindow().getDecorView();
   1295             decorView.removeAllViews();
   1296             View v1 = new MockView(mActivity);
   1297             v1.setFocusableInTouchMode(true);
   1298             View v2 = new MockView(mActivity);
   1299             v2.setFocusableInTouchMode(true);
   1300             decorView.addView(v1);
   1301             decorView.addView(v2);
   1302 
   1303             // Searching for clusters.
   1304             v1.setKeyboardNavigationCluster(true);
   1305             v2.setKeyboardNavigationCluster(true);
   1306             assertEquals(v2, decorView.keyboardNavigationClusterSearch(v1, View.FOCUS_FORWARD));
   1307             assertEquals(v1, decorView.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
   1308             assertEquals(v2, decorView.keyboardNavigationClusterSearch(null, View.FOCUS_BACKWARD));
   1309             assertEquals(v2, v1.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
   1310             assertEquals(decorView, v1.keyboardNavigationClusterSearch(null, View.FOCUS_BACKWARD));
   1311             assertEquals(decorView, v2.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
   1312             assertEquals(v1, v2.keyboardNavigationClusterSearch(null, View.FOCUS_BACKWARD));
   1313 
   1314             // Clusters in 3-level hierarchy.
   1315             decorView.removeAllViews();
   1316             LinearLayout middle = new LinearLayout(mActivity);
   1317             middle.addView(v1);
   1318             middle.addView(v2);
   1319             decorView.addView(middle);
   1320             assertEquals(decorView, v2.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD));
   1321         });
   1322     }
   1323 
   1324     @Test
   1325     public void testGetRootView() {
   1326         MockView view = new MockView(mActivity);
   1327 
   1328         assertNull(view.getParent());
   1329         assertEquals(view, view.getRootView());
   1330 
   1331         view.setParent(mMockParent);
   1332         assertEquals(mMockParent, view.getRootView());
   1333     }
   1334 
   1335     @Test
   1336     public void testGetSolidColor() {
   1337         View view = new View(mActivity);
   1338 
   1339         assertEquals(0, view.getSolidColor());
   1340     }
   1341 
   1342     @Test
   1343     public void testSetMinimumWidth() {
   1344         MockView view = new MockView(mActivity);
   1345         assertEquals(0, view.getSuggestedMinimumWidth());
   1346 
   1347         view.setMinimumWidth(100);
   1348         assertEquals(100, view.getSuggestedMinimumWidth());
   1349 
   1350         view.setMinimumWidth(-100);
   1351         assertEquals(-100, view.getSuggestedMinimumWidth());
   1352     }
   1353 
   1354     @Test
   1355     public void testGetSuggestedMinimumWidth() {
   1356         MockView view = new MockView(mActivity);
   1357         Drawable d = mResources.getDrawable(R.drawable.scenery);
   1358         int drawableMinimumWidth = d.getMinimumWidth();
   1359 
   1360         // drawable is null
   1361         view.setMinimumWidth(100);
   1362         assertNull(view.getBackground());
   1363         assertEquals(100, view.getSuggestedMinimumWidth());
   1364 
   1365         // drawable minimum width is larger than mMinWidth
   1366         view.setBackgroundDrawable(d);
   1367         view.setMinimumWidth(drawableMinimumWidth - 10);
   1368         assertEquals(drawableMinimumWidth, view.getSuggestedMinimumWidth());
   1369 
   1370         // drawable minimum width is smaller than mMinWidth
   1371         view.setMinimumWidth(drawableMinimumWidth + 10);
   1372         assertEquals(drawableMinimumWidth + 10, view.getSuggestedMinimumWidth());
   1373     }
   1374 
   1375     @Test
   1376     public void testSetMinimumHeight() {
   1377         MockView view = new MockView(mActivity);
   1378         assertEquals(0, view.getSuggestedMinimumHeight());
   1379 
   1380         view.setMinimumHeight(100);
   1381         assertEquals(100, view.getSuggestedMinimumHeight());
   1382 
   1383         view.setMinimumHeight(-100);
   1384         assertEquals(-100, view.getSuggestedMinimumHeight());
   1385     }
   1386 
   1387     @Test
   1388     public void testGetSuggestedMinimumHeight() {
   1389         MockView view = new MockView(mActivity);
   1390         Drawable d = mResources.getDrawable(R.drawable.scenery);
   1391         int drawableMinimumHeight = d.getMinimumHeight();
   1392 
   1393         // drawable is null
   1394         view.setMinimumHeight(100);
   1395         assertNull(view.getBackground());
   1396         assertEquals(100, view.getSuggestedMinimumHeight());
   1397 
   1398         // drawable minimum height is larger than mMinHeight
   1399         view.setBackgroundDrawable(d);
   1400         view.setMinimumHeight(drawableMinimumHeight - 10);
   1401         assertEquals(drawableMinimumHeight, view.getSuggestedMinimumHeight());
   1402 
   1403         // drawable minimum height is smaller than mMinHeight
   1404         view.setMinimumHeight(drawableMinimumHeight + 10);
   1405         assertEquals(drawableMinimumHeight + 10, view.getSuggestedMinimumHeight());
   1406     }
   1407 
   1408     @Test
   1409     public void testAccessWillNotCacheDrawing() {
   1410         View view = new View(mActivity);
   1411 
   1412         assertFalse(view.willNotCacheDrawing());
   1413 
   1414         view.setWillNotCacheDrawing(true);
   1415         assertTrue(view.willNotCacheDrawing());
   1416     }
   1417 
   1418     @Test
   1419     public void testAccessDrawingCacheEnabled() {
   1420         View view = new View(mActivity);
   1421 
   1422         assertFalse(view.isDrawingCacheEnabled());
   1423 
   1424         view.setDrawingCacheEnabled(true);
   1425         assertTrue(view.isDrawingCacheEnabled());
   1426     }
   1427 
   1428     @Test
   1429     public void testGetDrawingCache() {
   1430         MockView view = new MockView(mActivity);
   1431 
   1432         // should not call buildDrawingCache when getDrawingCache
   1433         assertNull(view.getDrawingCache());
   1434 
   1435         // should call buildDrawingCache when getDrawingCache
   1436         view = (MockView) mActivity.findViewById(R.id.mock_view);
   1437         view.setDrawingCacheEnabled(true);
   1438         Bitmap bitmap1 = view.getDrawingCache();
   1439         assertNotNull(bitmap1);
   1440         assertEquals(view.getWidth(), bitmap1.getWidth());
   1441         assertEquals(view.getHeight(), bitmap1.getHeight());
   1442 
   1443         view.setWillNotCacheDrawing(true);
   1444         assertNull(view.getDrawingCache());
   1445 
   1446         view.setWillNotCacheDrawing(false);
   1447         // build a new drawingcache
   1448         Bitmap bitmap2 = view.getDrawingCache();
   1449         assertNotSame(bitmap1, bitmap2);
   1450     }
   1451 
   1452     @Test
   1453     public void testBuildAndDestroyDrawingCache() {
   1454         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   1455 
   1456         assertNull(view.getDrawingCache());
   1457 
   1458         view.buildDrawingCache();
   1459         Bitmap bitmap = view.getDrawingCache();
   1460         assertNotNull(bitmap);
   1461         assertEquals(view.getWidth(), bitmap.getWidth());
   1462         assertEquals(view.getHeight(), bitmap.getHeight());
   1463 
   1464         view.destroyDrawingCache();
   1465         assertNull(view.getDrawingCache());
   1466     }
   1467 
   1468     @Test
   1469     public void testAccessWillNotDraw() {
   1470         View view = new View(mActivity);
   1471 
   1472         assertFalse(view.willNotDraw());
   1473 
   1474         view.setWillNotDraw(true);
   1475         assertTrue(view.willNotDraw());
   1476     }
   1477 
   1478     @Test
   1479     public void testAccessDrawingCacheQuality() {
   1480         View view = new View(mActivity);
   1481 
   1482         assertEquals(0, view.getDrawingCacheQuality());
   1483 
   1484         view.setDrawingCacheQuality(1);
   1485         assertEquals(0, view.getDrawingCacheQuality());
   1486 
   1487         view.setDrawingCacheQuality(0x00100000);
   1488         assertEquals(0x00100000, view.getDrawingCacheQuality());
   1489 
   1490         view.setDrawingCacheQuality(0x00080000);
   1491         assertEquals(0x00080000, view.getDrawingCacheQuality());
   1492 
   1493         view.setDrawingCacheQuality(0xffffffff);
   1494         // 0x00180000 is View.DRAWING_CACHE_QUALITY_MASK
   1495         assertEquals(0x00180000, view.getDrawingCacheQuality());
   1496     }
   1497 
   1498     @Test
   1499     public void testDispatchSetSelected() {
   1500         MockView mockView1 = new MockView(mActivity);
   1501         MockView mockView2 = new MockView(mActivity);
   1502         mockView1.setParent(mMockParent);
   1503         mockView2.setParent(mMockParent);
   1504 
   1505         mMockParent.dispatchSetSelected(true);
   1506         assertTrue(mockView1.isSelected());
   1507         assertTrue(mockView2.isSelected());
   1508 
   1509         mMockParent.dispatchSetSelected(false);
   1510         assertFalse(mockView1.isSelected());
   1511         assertFalse(mockView2.isSelected());
   1512     }
   1513 
   1514     @Test
   1515     public void testAccessSelected() {
   1516         View view = new View(mActivity);
   1517 
   1518         assertFalse(view.isSelected());
   1519 
   1520         view.setSelected(true);
   1521         assertTrue(view.isSelected());
   1522     }
   1523 
   1524     @Test
   1525     public void testDispatchSetPressed() {
   1526         MockView mockView1 = new MockView(mActivity);
   1527         MockView mockView2 = new MockView(mActivity);
   1528         mockView1.setParent(mMockParent);
   1529         mockView2.setParent(mMockParent);
   1530 
   1531         mMockParent.dispatchSetPressed(true);
   1532         assertTrue(mockView1.isPressed());
   1533         assertTrue(mockView2.isPressed());
   1534 
   1535         mMockParent.dispatchSetPressed(false);
   1536         assertFalse(mockView1.isPressed());
   1537         assertFalse(mockView2.isPressed());
   1538     }
   1539 
   1540     @Test
   1541     public void testAccessPressed() {
   1542         View view = new View(mActivity);
   1543 
   1544         assertFalse(view.isPressed());
   1545 
   1546         view.setPressed(true);
   1547         assertTrue(view.isPressed());
   1548     }
   1549 
   1550     @Test
   1551     public void testAccessSoundEffectsEnabled() {
   1552         View view = new View(mActivity);
   1553 
   1554         assertTrue(view.isSoundEffectsEnabled());
   1555 
   1556         view.setSoundEffectsEnabled(false);
   1557         assertFalse(view.isSoundEffectsEnabled());
   1558     }
   1559 
   1560     @Test
   1561     public void testAccessKeepScreenOn() {
   1562         View view = new View(mActivity);
   1563 
   1564         assertFalse(view.getKeepScreenOn());
   1565 
   1566         view.setKeepScreenOn(true);
   1567         assertTrue(view.getKeepScreenOn());
   1568     }
   1569 
   1570     @Test
   1571     public void testAccessDuplicateParentStateEnabled() {
   1572         View view = new View(mActivity);
   1573 
   1574         assertFalse(view.isDuplicateParentStateEnabled());
   1575 
   1576         view.setDuplicateParentStateEnabled(true);
   1577         assertTrue(view.isDuplicateParentStateEnabled());
   1578     }
   1579 
   1580     @Test
   1581     public void testAccessEnabled() {
   1582         View view = new View(mActivity);
   1583 
   1584         assertTrue(view.isEnabled());
   1585 
   1586         view.setEnabled(false);
   1587         assertFalse(view.isEnabled());
   1588     }
   1589 
   1590     @Test
   1591     public void testAccessSaveEnabled() {
   1592         View view = new View(mActivity);
   1593 
   1594         assertTrue(view.isSaveEnabled());
   1595 
   1596         view.setSaveEnabled(false);
   1597         assertFalse(view.isSaveEnabled());
   1598     }
   1599 
   1600     @Test(expected=NullPointerException.class)
   1601     public void testShowContextMenuNullParent() {
   1602         MockView view = new MockView(mActivity);
   1603 
   1604         assertNull(view.getParent());
   1605         view.showContextMenu();
   1606     }
   1607 
   1608     @Test
   1609     public void testShowContextMenu() {
   1610         MockView view = new MockView(mActivity);
   1611         view.setParent(mMockParent);
   1612         assertFalse(mMockParent.hasShowContextMenuForChild());
   1613 
   1614         assertFalse(view.showContextMenu());
   1615         assertTrue(mMockParent.hasShowContextMenuForChild());
   1616     }
   1617 
   1618     @Test(expected=NullPointerException.class)
   1619     public void testShowContextMenuXYNullParent() {
   1620         MockView view = new MockView(mActivity);
   1621 
   1622         assertNull(view.getParent());
   1623         view.showContextMenu(0, 0);
   1624     }
   1625 
   1626     @Test
   1627     public void testShowContextMenuXY() {
   1628         MockViewParent parent = new MockViewParent(mActivity);
   1629         MockView view = new MockView(mActivity);
   1630 
   1631         view.setParent(parent);
   1632         assertFalse(parent.hasShowContextMenuForChildXY());
   1633 
   1634         assertFalse(view.showContextMenu(0, 0));
   1635         assertTrue(parent.hasShowContextMenuForChildXY());
   1636     }
   1637 
   1638     @Test
   1639     public void testFitSystemWindows() {
   1640         final XmlResourceParser parser = mResources.getLayout(R.layout.view_layout);
   1641         final AttributeSet attrs = Xml.asAttributeSet(parser);
   1642         Rect insets = new Rect(10, 20, 30, 50);
   1643 
   1644         MockView view = new MockView(mActivity);
   1645         assertFalse(view.fitSystemWindows(insets));
   1646         assertFalse(view.fitSystemWindows(null));
   1647 
   1648         view = new MockView(mActivity, attrs, android.R.attr.fitsSystemWindows);
   1649         assertFalse(view.fitSystemWindows(insets));
   1650         assertFalse(view.fitSystemWindows(null));
   1651     }
   1652 
   1653     @Test
   1654     public void testPerformClick() {
   1655         View view = new View(mActivity);
   1656         View.OnClickListener listener = mock(View.OnClickListener.class);
   1657 
   1658         assertFalse(view.performClick());
   1659 
   1660         verifyZeroInteractions(listener);
   1661         view.setOnClickListener(listener);
   1662 
   1663         assertTrue(view.performClick());
   1664         verify(listener,times(1)).onClick(view);
   1665 
   1666         view.setOnClickListener(null);
   1667         assertFalse(view.performClick());
   1668     }
   1669 
   1670     @Test
   1671     public void testSetOnClickListener() {
   1672         View view = new View(mActivity);
   1673         assertFalse(view.performClick());
   1674         assertFalse(view.isClickable());
   1675 
   1676         view.setOnClickListener(null);
   1677         assertFalse(view.performClick());
   1678         assertTrue(view.isClickable());
   1679 
   1680         view.setOnClickListener(mock(View.OnClickListener.class));
   1681         assertTrue(view.performClick());
   1682         assertTrue(view.isClickable());
   1683     }
   1684 
   1685     @Test(expected=NullPointerException.class)
   1686     public void testPerformLongClickNullParent() {
   1687         MockView view = new MockView(mActivity);
   1688         view.performLongClick();
   1689     }
   1690 
   1691     @Test
   1692     public void testPerformLongClick() {
   1693         MockView view = new MockView(mActivity);
   1694         View.OnLongClickListener listener = mock(View.OnLongClickListener.class);
   1695         doReturn(true).when(listener).onLongClick(any());
   1696 
   1697         view.setParent(mMockParent);
   1698         assertFalse(mMockParent.hasShowContextMenuForChild());
   1699         assertFalse(view.performLongClick());
   1700         assertTrue(mMockParent.hasShowContextMenuForChild());
   1701 
   1702         view.setOnLongClickListener(listener);
   1703         mMockParent.reset();
   1704         assertFalse(mMockParent.hasShowContextMenuForChild());
   1705         verifyZeroInteractions(listener);
   1706         assertTrue(view.performLongClick());
   1707         assertFalse(mMockParent.hasShowContextMenuForChild());
   1708         verify(listener, times(1)).onLongClick(view);
   1709     }
   1710 
   1711     @Test(expected=NullPointerException.class)
   1712     public void testPerformLongClickXYNullParent() {
   1713         MockView view = new MockView(mActivity);
   1714         view.performLongClick(0, 0);
   1715     }
   1716 
   1717     @Test
   1718     public void testPerformLongClickXY() {
   1719         MockViewParent parent = new MockViewParent(mActivity);
   1720         MockView view = new MockView(mActivity);
   1721 
   1722         parent.addView(view);
   1723         assertFalse(parent.hasShowContextMenuForChildXY());
   1724 
   1725         // Verify default context menu behavior.
   1726         assertFalse(view.performLongClick(0, 0));
   1727         assertTrue(parent.hasShowContextMenuForChildXY());
   1728     }
   1729 
   1730     @Test
   1731     public void testPerformLongClickXY_WithListener() {
   1732         OnLongClickListener listener = mock(OnLongClickListener.class);
   1733         when(listener.onLongClick(any(View.class))).thenReturn(true);
   1734 
   1735         MockViewParent parent = new MockViewParent(mActivity);
   1736         MockView view = new MockView(mActivity);
   1737 
   1738         view.setOnLongClickListener(listener);
   1739         verify(listener, never()).onLongClick(any(View.class));
   1740 
   1741         parent.addView(view);
   1742         assertFalse(parent.hasShowContextMenuForChildXY());
   1743 
   1744         // Verify listener is preferred over default context menu.
   1745         assertTrue(view.performLongClick(0, 0));
   1746         assertFalse(parent.hasShowContextMenuForChildXY());
   1747         verify(listener).onLongClick(view);
   1748     }
   1749 
   1750     @Test
   1751     public void testSetOnLongClickListener() {
   1752         MockView view = new MockView(mActivity);
   1753         view.setParent(mMockParent);
   1754         assertFalse(view.performLongClick());
   1755         assertFalse(view.isLongClickable());
   1756 
   1757         view.setOnLongClickListener(null);
   1758         assertFalse(view.performLongClick());
   1759         assertTrue(view.isLongClickable());
   1760 
   1761         View.OnLongClickListener listener = mock(View.OnLongClickListener.class);
   1762         doReturn(true).when(listener).onLongClick(any());
   1763         view.setOnLongClickListener(listener);
   1764         assertTrue(view.performLongClick());
   1765         assertTrue(view.isLongClickable());
   1766     }
   1767 
   1768     @Test
   1769     public void testPerformContextClick() {
   1770         MockView view = new MockView(mActivity);
   1771         view.setParent(mMockParent);
   1772         View.OnContextClickListener listener = mock(View.OnContextClickListener.class);
   1773         doReturn(true).when(listener).onContextClick(any());
   1774 
   1775         view.setOnContextClickListener(listener);
   1776         verifyZeroInteractions(listener);
   1777 
   1778         assertTrue(view.performContextClick());
   1779         verify(listener, times(1)).onContextClick(view);
   1780     }
   1781 
   1782     @Test
   1783     public void testSetOnContextClickListener() {
   1784         MockView view = new MockView(mActivity);
   1785         view.setParent(mMockParent);
   1786 
   1787         assertFalse(view.performContextClick());
   1788         assertFalse(view.isContextClickable());
   1789 
   1790         View.OnContextClickListener listener = mock(View.OnContextClickListener.class);
   1791         doReturn(true).when(listener).onContextClick(any());
   1792         view.setOnContextClickListener(listener);
   1793         assertTrue(view.performContextClick());
   1794         assertTrue(view.isContextClickable());
   1795     }
   1796 
   1797     @Test
   1798     public void testAccessOnFocusChangeListener() {
   1799         View view = new View(mActivity);
   1800         View.OnFocusChangeListener listener = mock(View.OnFocusChangeListener.class);
   1801 
   1802         assertNull(view.getOnFocusChangeListener());
   1803 
   1804         view.setOnFocusChangeListener(listener);
   1805         assertSame(listener, view.getOnFocusChangeListener());
   1806     }
   1807 
   1808     @Test
   1809     public void testAccessNextFocusUpId() {
   1810         View view = new View(mActivity);
   1811 
   1812         assertEquals(View.NO_ID, view.getNextFocusUpId());
   1813 
   1814         view.setNextFocusUpId(1);
   1815         assertEquals(1, view.getNextFocusUpId());
   1816 
   1817         view.setNextFocusUpId(Integer.MAX_VALUE);
   1818         assertEquals(Integer.MAX_VALUE, view.getNextFocusUpId());
   1819 
   1820         view.setNextFocusUpId(Integer.MIN_VALUE);
   1821         assertEquals(Integer.MIN_VALUE, view.getNextFocusUpId());
   1822     }
   1823 
   1824     @Test
   1825     public void testAccessNextFocusDownId() {
   1826         View view = new View(mActivity);
   1827 
   1828         assertEquals(View.NO_ID, view.getNextFocusDownId());
   1829 
   1830         view.setNextFocusDownId(1);
   1831         assertEquals(1, view.getNextFocusDownId());
   1832 
   1833         view.setNextFocusDownId(Integer.MAX_VALUE);
   1834         assertEquals(Integer.MAX_VALUE, view.getNextFocusDownId());
   1835 
   1836         view.setNextFocusDownId(Integer.MIN_VALUE);
   1837         assertEquals(Integer.MIN_VALUE, view.getNextFocusDownId());
   1838     }
   1839 
   1840     @Test
   1841     public void testAccessNextFocusLeftId() {
   1842         View view = new View(mActivity);
   1843 
   1844         assertEquals(View.NO_ID, view.getNextFocusLeftId());
   1845 
   1846         view.setNextFocusLeftId(1);
   1847         assertEquals(1, view.getNextFocusLeftId());
   1848 
   1849         view.setNextFocusLeftId(Integer.MAX_VALUE);
   1850         assertEquals(Integer.MAX_VALUE, view.getNextFocusLeftId());
   1851 
   1852         view.setNextFocusLeftId(Integer.MIN_VALUE);
   1853         assertEquals(Integer.MIN_VALUE, view.getNextFocusLeftId());
   1854     }
   1855 
   1856     @Test
   1857     public void testAccessNextFocusRightId() {
   1858         View view = new View(mActivity);
   1859 
   1860         assertEquals(View.NO_ID, view.getNextFocusRightId());
   1861 
   1862         view.setNextFocusRightId(1);
   1863         assertEquals(1, view.getNextFocusRightId());
   1864 
   1865         view.setNextFocusRightId(Integer.MAX_VALUE);
   1866         assertEquals(Integer.MAX_VALUE, view.getNextFocusRightId());
   1867 
   1868         view.setNextFocusRightId(Integer.MIN_VALUE);
   1869         assertEquals(Integer.MIN_VALUE, view.getNextFocusRightId());
   1870     }
   1871 
   1872     @Test
   1873     public void testAccessMeasuredDimension() {
   1874         MockView view = new MockView(mActivity);
   1875         assertEquals(0, view.getMeasuredWidth());
   1876         assertEquals(0, view.getMeasuredHeight());
   1877 
   1878         view.setMeasuredDimensionWrapper(20, 30);
   1879         assertEquals(20, view.getMeasuredWidth());
   1880         assertEquals(30, view.getMeasuredHeight());
   1881     }
   1882 
   1883     @Test
   1884     public void testMeasure() throws Throwable {
   1885         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   1886         assertTrue(view.hasCalledOnMeasure());
   1887         assertEquals(100, view.getMeasuredWidth());
   1888         assertEquals(200, view.getMeasuredHeight());
   1889 
   1890         view.reset();
   1891         mActivityRule.runOnUiThread(view::requestLayout);
   1892         mInstrumentation.waitForIdleSync();
   1893         assertTrue(view.hasCalledOnMeasure());
   1894         assertEquals(100, view.getMeasuredWidth());
   1895         assertEquals(200, view.getMeasuredHeight());
   1896 
   1897         view.reset();
   1898         final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(200, 100);
   1899         mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams));
   1900         mInstrumentation.waitForIdleSync();
   1901         assertTrue(view.hasCalledOnMeasure());
   1902         assertEquals(200, view.getMeasuredWidth());
   1903         assertEquals(100, view.getMeasuredHeight());
   1904     }
   1905 
   1906     @Test(expected=NullPointerException.class)
   1907     public void setSetLayoutParamsNull() {
   1908         View view = new View(mActivity);
   1909         assertNull(view.getLayoutParams());
   1910 
   1911         view.setLayoutParams(null);
   1912     }
   1913 
   1914     @Test
   1915     public void testAccessLayoutParams() {
   1916         View view = new View(mActivity);
   1917         ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(10, 20);
   1918 
   1919         assertFalse(view.isLayoutRequested());
   1920         view.setLayoutParams(params);
   1921         assertSame(params, view.getLayoutParams());
   1922         assertTrue(view.isLayoutRequested());
   1923     }
   1924 
   1925     @Test
   1926     public void testIsShown() {
   1927         MockView view = new MockView(mActivity);
   1928 
   1929         view.setVisibility(View.INVISIBLE);
   1930         assertFalse(view.isShown());
   1931 
   1932         view.setVisibility(View.VISIBLE);
   1933         assertNull(view.getParent());
   1934         assertFalse(view.isShown());
   1935 
   1936         view.setParent(mMockParent);
   1937         // mMockParent is not a instance of ViewRoot
   1938         assertFalse(view.isShown());
   1939     }
   1940 
   1941     @Test
   1942     public void testGetDrawingTime() {
   1943         View view = new View(mActivity);
   1944         // mAttachInfo is null
   1945         assertEquals(0, view.getDrawingTime());
   1946 
   1947         // mAttachInfo is not null
   1948         view = mActivity.findViewById(R.id.fit_windows);
   1949         assertEquals(SystemClock.uptimeMillis(), view.getDrawingTime(), 1000);
   1950     }
   1951 
   1952     @Test
   1953     public void testScheduleDrawable() {
   1954         View view = new View(mActivity);
   1955         Drawable drawable = new StateListDrawable();
   1956         // Does nothing.
   1957         Runnable what = () -> {};
   1958         // mAttachInfo is null
   1959         view.scheduleDrawable(drawable, what, 1000);
   1960 
   1961         view.setBackgroundDrawable(drawable);
   1962         view.scheduleDrawable(drawable, what, 1000);
   1963 
   1964         view.scheduleDrawable(null, null, -1000);
   1965 
   1966         // mAttachInfo is not null
   1967         view = mActivity.findViewById(R.id.fit_windows);
   1968         view.scheduleDrawable(drawable, what, 1000);
   1969 
   1970         view.scheduleDrawable(view.getBackground(), what, 1000);
   1971         view.unscheduleDrawable(view.getBackground(), what);
   1972 
   1973         view.scheduleDrawable(null, null, -1000);
   1974     }
   1975 
   1976     @Test
   1977     public void testUnscheduleDrawable() {
   1978         View view = new View(mActivity);
   1979         Drawable drawable = new StateListDrawable();
   1980         Runnable what = () -> {
   1981             // do nothing
   1982         };
   1983 
   1984         // mAttachInfo is null
   1985         view.unscheduleDrawable(drawable, what);
   1986 
   1987         view.setBackgroundDrawable(drawable);
   1988         view.unscheduleDrawable(drawable);
   1989 
   1990         view.unscheduleDrawable(null, null);
   1991         view.unscheduleDrawable(null);
   1992 
   1993         // mAttachInfo is not null
   1994         view = mActivity.findViewById(R.id.fit_windows);
   1995         view.unscheduleDrawable(drawable);
   1996 
   1997         view.scheduleDrawable(view.getBackground(), what, 1000);
   1998         view.unscheduleDrawable(view.getBackground(), what);
   1999 
   2000         view.unscheduleDrawable(null);
   2001         view.unscheduleDrawable(null, null);
   2002     }
   2003 
   2004     @Test
   2005     public void testGetWindowVisibility() {
   2006         View view = new View(mActivity);
   2007         // mAttachInfo is null
   2008         assertEquals(View.GONE, view.getWindowVisibility());
   2009 
   2010         // mAttachInfo is not null
   2011         view = mActivity.findViewById(R.id.fit_windows);
   2012         assertEquals(View.VISIBLE, view.getWindowVisibility());
   2013     }
   2014 
   2015     @Test
   2016     public void testGetWindowToken() {
   2017         View view = new View(mActivity);
   2018         // mAttachInfo is null
   2019         assertNull(view.getWindowToken());
   2020 
   2021         // mAttachInfo is not null
   2022         view = mActivity.findViewById(R.id.fit_windows);
   2023         assertNotNull(view.getWindowToken());
   2024     }
   2025 
   2026     @Test
   2027     public void testHasWindowFocus() {
   2028         View view = new View(mActivity);
   2029         // mAttachInfo is null
   2030         assertFalse(view.hasWindowFocus());
   2031 
   2032         // mAttachInfo is not null
   2033         final View view2 = mActivity.findViewById(R.id.fit_windows);
   2034         // Wait until the window has been focused.
   2035         PollingCheck.waitFor(TIMEOUT_DELTA, view2::hasWindowFocus);
   2036     }
   2037 
   2038     @Test
   2039     public void testGetHandler() {
   2040         MockView view = new MockView(mActivity);
   2041         // mAttachInfo is null
   2042         assertNull(view.getHandler());
   2043     }
   2044 
   2045     @Test
   2046     public void testRemoveCallbacks() throws InterruptedException {
   2047         final long delay = 500L;
   2048         View view = mActivity.findViewById(R.id.mock_view);
   2049         Runnable runner = mock(Runnable.class);
   2050         assertTrue(view.postDelayed(runner, delay));
   2051         assertTrue(view.removeCallbacks(runner));
   2052         assertTrue(view.removeCallbacks(null));
   2053         assertTrue(view.removeCallbacks(mock(Runnable.class)));
   2054         Thread.sleep(delay * 2);
   2055         verifyZeroInteractions(runner);
   2056         // check that the runner actually works
   2057         runner = mock(Runnable.class);
   2058         assertTrue(view.postDelayed(runner, delay));
   2059         Thread.sleep(delay * 2);
   2060         verify(runner, times(1)).run();
   2061     }
   2062 
   2063     @Test
   2064     public void testCancelLongPress() {
   2065         View view = new View(mActivity);
   2066         // mAttachInfo is null
   2067         view.cancelLongPress();
   2068 
   2069         // mAttachInfo is not null
   2070         view = mActivity.findViewById(R.id.fit_windows);
   2071         view.cancelLongPress();
   2072     }
   2073 
   2074     @Test
   2075     public void testGetViewTreeObserver() {
   2076         View view = new View(mActivity);
   2077         // mAttachInfo is null
   2078         assertNotNull(view.getViewTreeObserver());
   2079 
   2080         // mAttachInfo is not null
   2081         view = mActivity.findViewById(R.id.fit_windows);
   2082         assertNotNull(view.getViewTreeObserver());
   2083     }
   2084 
   2085     @Test
   2086     public void testGetWindowAttachCount() {
   2087         MockView view = new MockView(mActivity);
   2088         // mAttachInfo is null
   2089         assertEquals(0, view.getWindowAttachCount());
   2090     }
   2091 
   2092     @UiThreadTest
   2093     @Test
   2094     public void testOnAttachedToAndDetachedFromWindow() {
   2095         MockView mockView = new MockView(mActivity);
   2096         ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
   2097 
   2098         viewGroup.addView(mockView);
   2099         assertTrue(mockView.hasCalledOnAttachedToWindow());
   2100 
   2101         viewGroup.removeView(mockView);
   2102         assertTrue(mockView.hasCalledOnDetachedFromWindow());
   2103 
   2104         mockView.reset();
   2105         mActivity.setContentView(mockView);
   2106         assertTrue(mockView.hasCalledOnAttachedToWindow());
   2107 
   2108         mActivity.setContentView(R.layout.view_layout);
   2109         assertTrue(mockView.hasCalledOnDetachedFromWindow());
   2110     }
   2111 
   2112     @Test
   2113     public void testGetLocationInWindow() {
   2114         final int[] location = new int[]{-1, -1};
   2115 
   2116         final View layout = mActivity.findViewById(R.id.viewlayout_root);
   2117         int[] layoutLocation = new int[]{-1, -1};
   2118         layout.getLocationInWindow(layoutLocation);
   2119 
   2120         final View mockView = mActivity.findViewById(R.id.mock_view);
   2121         mockView.getLocationInWindow(location);
   2122         assertEquals(layoutLocation[0], location[0]);
   2123         assertEquals(layoutLocation[1], location[1]);
   2124 
   2125         final View scrollView = mActivity.findViewById(R.id.scroll_view);
   2126         scrollView.getLocationInWindow(location);
   2127         assertEquals(layoutLocation[0], location[0]);
   2128         assertEquals(layoutLocation[1] + mockView.getHeight(), location[1]);
   2129     }
   2130 
   2131     @Test(expected=IllegalArgumentException.class)
   2132     public void testGetLocationInWindowNullArray() {
   2133         final View layout = mActivity.findViewById(R.id.viewlayout_root);
   2134         final View mockView = mActivity.findViewById(R.id.mock_view);
   2135 
   2136         mockView.getLocationInWindow(null);
   2137     }
   2138 
   2139     @Test(expected=IllegalArgumentException.class)
   2140     public void testGetLocationInWindowSmallArray() {
   2141         final View layout = mActivity.findViewById(R.id.viewlayout_root);
   2142         final View mockView = mActivity.findViewById(R.id.mock_view);
   2143 
   2144         mockView.getLocationInWindow(new int[] { 0 });
   2145     }
   2146 
   2147     @Test
   2148     public void testGetLocationOnScreen() {
   2149         final int[] location = new int[]{-1, -1};
   2150 
   2151         // mAttachInfo is not null
   2152         final View layout = mActivity.findViewById(R.id.viewlayout_root);
   2153         final int[] layoutLocation = new int[]{-1, -1};
   2154         layout.getLocationOnScreen(layoutLocation);
   2155 
   2156         final View mockView = mActivity.findViewById(R.id.mock_view);
   2157         mockView.getLocationOnScreen(location);
   2158         assertEquals(layoutLocation[0], location[0]);
   2159         assertEquals(layoutLocation[1], location[1]);
   2160 
   2161         final View scrollView = mActivity.findViewById(R.id.scroll_view);
   2162         scrollView.getLocationOnScreen(location);
   2163         assertEquals(layoutLocation[0], location[0]);
   2164         assertEquals(layoutLocation[1] + mockView.getHeight(), location[1]);
   2165     }
   2166 
   2167     @Test(expected=IllegalArgumentException.class)
   2168     public void testGetLocationOnScreenNullArray() {
   2169         final View scrollView = mActivity.findViewById(R.id.scroll_view);
   2170 
   2171         scrollView.getLocationOnScreen(null);
   2172     }
   2173 
   2174     @Test(expected=IllegalArgumentException.class)
   2175     public void testGetLocationOnScreenSmallArray() {
   2176         final View scrollView = mActivity.findViewById(R.id.scroll_view);
   2177 
   2178         scrollView.getLocationOnScreen(new int[] { 0 });
   2179     }
   2180 
   2181     @Test
   2182     public void testAddTouchables() {
   2183         View view = new View(mActivity);
   2184         ArrayList<View> result = new ArrayList<>();
   2185         assertEquals(0, result.size());
   2186 
   2187         view.addTouchables(result);
   2188         assertEquals(0, result.size());
   2189 
   2190         view.setClickable(true);
   2191         view.addTouchables(result);
   2192         assertEquals(1, result.size());
   2193         assertSame(view, result.get(0));
   2194 
   2195         try {
   2196             view.addTouchables(null);
   2197             fail("should throw NullPointerException");
   2198         } catch (NullPointerException e) {
   2199         }
   2200 
   2201         result.clear();
   2202         view.setEnabled(false);
   2203         assertTrue(view.isClickable());
   2204         view.addTouchables(result);
   2205         assertEquals(0, result.size());
   2206     }
   2207 
   2208     @Test
   2209     public void testGetTouchables() {
   2210         View view = new View(mActivity);
   2211         ArrayList<View> result;
   2212 
   2213         result = view.getTouchables();
   2214         assertEquals(0, result.size());
   2215 
   2216         view.setClickable(true);
   2217         result = view.getTouchables();
   2218         assertEquals(1, result.size());
   2219         assertSame(view, result.get(0));
   2220 
   2221         result.clear();
   2222         view.setEnabled(false);
   2223         assertTrue(view.isClickable());
   2224         result = view.getTouchables();
   2225         assertEquals(0, result.size());
   2226     }
   2227 
   2228     @Test
   2229     public void testInflate() {
   2230         View view = View.inflate(mActivity, R.layout.view_layout, null);
   2231         assertNotNull(view);
   2232         assertTrue(view instanceof LinearLayout);
   2233 
   2234         MockView mockView = (MockView) view.findViewById(R.id.mock_view);
   2235         assertNotNull(mockView);
   2236         assertTrue(mockView.hasCalledOnFinishInflate());
   2237     }
   2238 
   2239     @Test
   2240     public void testIsInTouchMode() {
   2241         View view = new View(mActivity);
   2242         // mAttachInfo is null
   2243         assertFalse(view.isInTouchMode());
   2244 
   2245         // mAttachInfo is not null
   2246         view = mActivity.findViewById(R.id.fit_windows);
   2247         assertFalse(view.isInTouchMode());
   2248     }
   2249 
   2250     @Test
   2251     public void testIsInEditMode() {
   2252         View view = new View(mActivity);
   2253         assertFalse(view.isInEditMode());
   2254     }
   2255 
   2256     @Test
   2257     public void testPostInvalidate1() {
   2258         View view = new View(mActivity);
   2259         // mAttachInfo is null
   2260         view.postInvalidate();
   2261 
   2262         // mAttachInfo is not null
   2263         view = mActivity.findViewById(R.id.fit_windows);
   2264         view.postInvalidate();
   2265     }
   2266 
   2267     @Test
   2268     public void testPostInvalidate2() {
   2269         View view = new View(mActivity);
   2270         // mAttachInfo is null
   2271         view.postInvalidate(0, 1, 2, 3);
   2272 
   2273         // mAttachInfo is not null
   2274         view = mActivity.findViewById(R.id.fit_windows);
   2275         view.postInvalidate(10, 20, 30, 40);
   2276         view.postInvalidate(0, -20, -30, -40);
   2277     }
   2278 
   2279     @Test
   2280     public void testPostInvalidateDelayed() {
   2281         View view = new View(mActivity);
   2282         // mAttachInfo is null
   2283         view.postInvalidateDelayed(1000);
   2284         view.postInvalidateDelayed(500, 0, 0, 100, 200);
   2285 
   2286         // mAttachInfo is not null
   2287         view = mActivity.findViewById(R.id.fit_windows);
   2288         view.postInvalidateDelayed(1000);
   2289         view.postInvalidateDelayed(500, 0, 0, 100, 200);
   2290         view.postInvalidateDelayed(-1);
   2291     }
   2292 
   2293     @Test
   2294     public void testPost() {
   2295         View view = new View(mActivity);
   2296         Runnable action = mock(Runnable.class);
   2297 
   2298         // mAttachInfo is null
   2299         assertTrue(view.post(action));
   2300         assertTrue(view.post(null));
   2301 
   2302         // mAttachInfo is not null
   2303         view = mActivity.findViewById(R.id.fit_windows);
   2304         assertTrue(view.post(action));
   2305         assertTrue(view.post(null));
   2306     }
   2307 
   2308     @Test
   2309     public void testPostDelayed() {
   2310         View view = new View(mActivity);
   2311         Runnable action = mock(Runnable.class);
   2312 
   2313         // mAttachInfo is null
   2314         assertTrue(view.postDelayed(action, 1000));
   2315         assertTrue(view.postDelayed(null, -1));
   2316 
   2317         // mAttachInfo is not null
   2318         view = mActivity.findViewById(R.id.fit_windows);
   2319         assertTrue(view.postDelayed(action, 1000));
   2320         assertTrue(view.postDelayed(null, 0));
   2321     }
   2322 
   2323     @UiThreadTest
   2324     @Test
   2325     public void testPlaySoundEffect() {
   2326         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   2327         // sound effect enabled
   2328         view.playSoundEffect(SoundEffectConstants.CLICK);
   2329 
   2330         // sound effect disabled
   2331         view.setSoundEffectsEnabled(false);
   2332         view.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
   2333 
   2334         // no way to assert the soundConstant be really played.
   2335     }
   2336 
   2337     @Test
   2338     public void testOnKeyShortcut() throws Throwable {
   2339         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   2340         mActivityRule.runOnUiThread(() -> {
   2341             view.setFocusable(true);
   2342             view.requestFocus();
   2343         });
   2344         mInstrumentation.waitForIdleSync();
   2345         assertTrue(view.isFocused());
   2346 
   2347         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU);
   2348         mInstrumentation.sendKeySync(event);
   2349         event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
   2350         mInstrumentation.sendKeySync(event);
   2351         assertTrue(view.hasCalledOnKeyShortcut());
   2352     }
   2353 
   2354     @Test
   2355     public void testOnKeyMultiple() throws Throwable {
   2356         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   2357         mActivityRule.runOnUiThread(() -> view.setFocusable(true));
   2358 
   2359         assertFalse(view.hasCalledOnKeyMultiple());
   2360         view.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_ENTER));
   2361         assertTrue(view.hasCalledOnKeyMultiple());
   2362     }
   2363 
   2364     @UiThreadTest
   2365     @Test
   2366     public void testDispatchKeyShortcutEvent() {
   2367         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   2368         view.setFocusable(true);
   2369 
   2370         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
   2371         view.dispatchKeyShortcutEvent(event);
   2372         assertTrue(view.hasCalledOnKeyShortcut());
   2373     }
   2374 
   2375     @UiThreadTest
   2376     @Test(expected=NullPointerException.class)
   2377     public void testDispatchKeyShortcutEventNull() {
   2378         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   2379         view.setFocusable(true);
   2380 
   2381         view.dispatchKeyShortcutEvent(null);
   2382     }
   2383 
   2384     @Test
   2385     public void testOnTrackballEvent() throws Throwable {
   2386         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   2387         mActivityRule.runOnUiThread(() -> {
   2388             view.setEnabled(true);
   2389             view.setFocusable(true);
   2390             view.requestFocus();
   2391         });
   2392         mInstrumentation.waitForIdleSync();
   2393 
   2394         long downTime = SystemClock.uptimeMillis();
   2395         long eventTime = downTime;
   2396         MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
   2397                 1, 2, 0);
   2398         mInstrumentation.sendTrackballEventSync(event);
   2399         mInstrumentation.waitForIdleSync();
   2400         assertTrue(view.hasCalledOnTrackballEvent());
   2401     }
   2402 
   2403     @UiThreadTest
   2404     @Test
   2405     public void testDispatchTrackballMoveEvent() {
   2406         ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
   2407         MockView mockView1 = new MockView(mActivity);
   2408         MockView mockView2 = new MockView(mActivity);
   2409         viewGroup.addView(mockView1);
   2410         viewGroup.addView(mockView2);
   2411         mockView1.setFocusable(true);
   2412         mockView2.setFocusable(true);
   2413         mockView2.requestFocus();
   2414 
   2415         long downTime = SystemClock.uptimeMillis();
   2416         long eventTime = downTime;
   2417         MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
   2418                 1, 2, 0);
   2419         mockView1.dispatchTrackballEvent(event);
   2420         // issue 1695243
   2421         // It passes a trackball motion event down to itself even if it is not the focused view.
   2422         assertTrue(mockView1.hasCalledOnTrackballEvent());
   2423         assertFalse(mockView2.hasCalledOnTrackballEvent());
   2424 
   2425         mockView1.reset();
   2426         mockView2.reset();
   2427         downTime = SystemClock.uptimeMillis();
   2428         eventTime = downTime;
   2429         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, 1, 2, 0);
   2430         mockView2.dispatchTrackballEvent(event);
   2431         assertFalse(mockView1.hasCalledOnTrackballEvent());
   2432         assertTrue(mockView2.hasCalledOnTrackballEvent());
   2433     }
   2434 
   2435     @Test
   2436     public void testDispatchUnhandledMove() throws Throwable {
   2437         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   2438         mActivityRule.runOnUiThread(() -> {
   2439             view.setFocusable(true);
   2440             view.requestFocus();
   2441         });
   2442         mInstrumentation.waitForIdleSync();
   2443 
   2444         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT);
   2445         mInstrumentation.sendKeySync(event);
   2446 
   2447         assertTrue(view.hasCalledDispatchUnhandledMove());
   2448     }
   2449 
   2450     @Test
   2451     public void testUnhandledKeys() throws Throwable {
   2452         MockUnhandledKeyListener listener = new MockUnhandledKeyListener();
   2453         ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
   2454         // Attaching a fallback handler
   2455         TextView mockView1 = new TextView(mActivity);
   2456         mockView1.addOnUnhandledKeyEventListener(listener);
   2457 
   2458         // Before the view is attached, it shouldn't respond to anything
   2459         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
   2460         assertFalse(listener.fired());
   2461 
   2462         // Once attached, it should start receiving fallback events
   2463         mActivityRule.runOnUiThread(() -> viewGroup.addView(mockView1));
   2464         mInstrumentation.waitForIdleSync();
   2465         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
   2466         assertTrue(listener.fired());
   2467         listener.reset();
   2468 
   2469         // If multiple on one view, last added should receive event first
   2470         MockUnhandledKeyListener listener2 = new MockUnhandledKeyListener();
   2471         listener2.mReturnVal = true;
   2472         mActivityRule.runOnUiThread(() -> mockView1.addOnUnhandledKeyEventListener(listener2));
   2473         mInstrumentation.waitForIdleSync();
   2474         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
   2475         assertTrue(listener2.fired());
   2476         assertFalse(listener.fired());
   2477         listener2.reset();
   2478 
   2479         // If removed, it should not receive fallbacks anymore
   2480         mActivityRule.runOnUiThread(() -> {
   2481             mockView1.removeOnUnhandledKeyEventListener(listener);
   2482             mockView1.removeOnUnhandledKeyEventListener(listener2);
   2483         });
   2484         mInstrumentation.waitForIdleSync();
   2485         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
   2486         assertFalse(listener.fired());
   2487 
   2488         mActivityRule.runOnUiThread(() -> mActivity.setContentView(R.layout.key_fallback_layout));
   2489         mInstrumentation.waitForIdleSync();
   2490         View higherInNormal = mActivity.findViewById(R.id.higher_in_normal);
   2491         View higherGroup = mActivity.findViewById(R.id.higher_group);
   2492         View lowerInHigher = mActivity.findViewById(R.id.lower_in_higher);
   2493         View lastButton = mActivity.findViewById(R.id.last_button);
   2494         View lastInHigher = mActivity.findViewById(R.id.last_in_higher);
   2495         View lastInNormal = mActivity.findViewById(R.id.last_in_normal);
   2496 
   2497         View[] allViews = new View[]{higherInNormal, higherGroup, lowerInHigher, lastButton,
   2498                 lastInHigher, lastInNormal};
   2499 
   2500         // Test ordering by depth
   2501         listener.mReturnVal = true;
   2502         mActivityRule.runOnUiThread(() -> {
   2503             for (View v : allViews) {
   2504                 v.addOnUnhandledKeyEventListener(listener);
   2505             }
   2506         });
   2507         mInstrumentation.waitForIdleSync();
   2508 
   2509         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
   2510         assertEquals(lastInHigher, listener.mLastView);
   2511         listener.reset();
   2512 
   2513         mActivityRule.runOnUiThread(
   2514                 () -> lastInHigher.removeOnUnhandledKeyEventListener(listener));
   2515         mInstrumentation.waitForIdleSync();
   2516         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
   2517         assertEquals(lowerInHigher, listener.mLastView);
   2518         listener.reset();
   2519 
   2520         mActivityRule.runOnUiThread(
   2521                 () -> lowerInHigher.removeOnUnhandledKeyEventListener(listener));
   2522         mInstrumentation.waitForIdleSync();
   2523         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
   2524         assertEquals(higherGroup, listener.mLastView);
   2525         listener.reset();
   2526 
   2527         mActivityRule.runOnUiThread(() -> higherGroup.removeOnUnhandledKeyEventListener(listener));
   2528         mInstrumentation.waitForIdleSync();
   2529         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
   2530         assertEquals(lastButton, listener.mLastView);
   2531         listener.reset();
   2532 
   2533         mActivityRule.runOnUiThread(() -> lastButton.removeOnUnhandledKeyEventListener(listener));
   2534         mInstrumentation.waitForIdleSync();
   2535         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
   2536         assertEquals(higherInNormal, listener.mLastView);
   2537         listener.reset();
   2538 
   2539         mActivityRule.runOnUiThread(
   2540                 () -> higherInNormal.removeOnUnhandledKeyEventListener(listener));
   2541         mInstrumentation.waitForIdleSync();
   2542         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
   2543         assertEquals(lastInNormal, listener.mLastView);
   2544         listener.reset();
   2545 
   2546         // Test "capture"
   2547         mActivityRule.runOnUiThread(() -> lastInNormal.requestFocus());
   2548         mInstrumentation.waitForIdleSync();
   2549         lastInNormal.setOnKeyListener((v, keyCode, event)
   2550                 -> (keyCode == KeyEvent.KEYCODE_B && event.getAction() == KeyEvent.ACTION_UP));
   2551         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
   2552         assertTrue(listener.fired()); // checks that both up and down were received
   2553         listener.reset();
   2554     }
   2555 
   2556     @Test
   2557     public void testWindowVisibilityChanged() throws Throwable {
   2558         final MockView mockView = new MockView(mActivity);
   2559         final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
   2560 
   2561         mActivityRule.runOnUiThread(() -> viewGroup.addView(mockView));
   2562         mInstrumentation.waitForIdleSync();
   2563         assertTrue(mockView.hasCalledOnWindowVisibilityChanged());
   2564 
   2565         mockView.reset();
   2566         mActivityRule.runOnUiThread(() -> mActivity.setVisible(false));
   2567         mInstrumentation.waitForIdleSync();
   2568         assertTrue(mockView.hasCalledDispatchWindowVisibilityChanged());
   2569         assertTrue(mockView.hasCalledOnWindowVisibilityChanged());
   2570 
   2571         mockView.reset();
   2572         mActivityRule.runOnUiThread(() -> mActivity.setVisible(true));
   2573         mInstrumentation.waitForIdleSync();
   2574         assertTrue(mockView.hasCalledDispatchWindowVisibilityChanged());
   2575         assertTrue(mockView.hasCalledOnWindowVisibilityChanged());
   2576 
   2577         mockView.reset();
   2578         mActivityRule.runOnUiThread(() -> viewGroup.removeView(mockView));
   2579         mInstrumentation.waitForIdleSync();
   2580         assertTrue(mockView.hasCalledOnWindowVisibilityChanged());
   2581     }
   2582 
   2583     @Test
   2584     public void testGetLocalVisibleRect() throws Throwable {
   2585         final View view = mActivity.findViewById(R.id.mock_view);
   2586         Rect rect = new Rect();
   2587 
   2588         assertTrue(view.getLocalVisibleRect(rect));
   2589         assertEquals(0, rect.left);
   2590         assertEquals(0, rect.top);
   2591         assertEquals(100, rect.right);
   2592         assertEquals(200, rect.bottom);
   2593 
   2594         final LinearLayout.LayoutParams layoutParams1 = new LinearLayout.LayoutParams(0, 300);
   2595         mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams1));
   2596         mInstrumentation.waitForIdleSync();
   2597         assertFalse(view.getLocalVisibleRect(rect));
   2598 
   2599         final LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams(200, -10);
   2600         mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams2));
   2601         mInstrumentation.waitForIdleSync();
   2602         assertFalse(view.getLocalVisibleRect(rect));
   2603 
   2604         Display display = mActivity.getWindowManager().getDefaultDisplay();
   2605         int halfWidth = display.getWidth() / 2;
   2606         int halfHeight = display.getHeight() /2;
   2607 
   2608         final LinearLayout.LayoutParams layoutParams3 =
   2609                 new LinearLayout.LayoutParams(halfWidth, halfHeight);
   2610         mActivityRule.runOnUiThread(() -> {
   2611             view.setLayoutParams(layoutParams3);
   2612             view.scrollTo(20, -30);
   2613         });
   2614         mInstrumentation.waitForIdleSync();
   2615         assertTrue(view.getLocalVisibleRect(rect));
   2616         assertEquals(20, rect.left);
   2617         assertEquals(-30, rect.top);
   2618         assertEquals(halfWidth + 20, rect.right);
   2619         assertEquals(halfHeight - 30, rect.bottom);
   2620 
   2621         try {
   2622             view.getLocalVisibleRect(null);
   2623             fail("should throw NullPointerException");
   2624         } catch (NullPointerException e) {
   2625         }
   2626     }
   2627 
   2628     @Test
   2629     public void testMergeDrawableStates() {
   2630         MockView view = new MockView(mActivity);
   2631 
   2632         int[] states = view.mergeDrawableStatesWrapper(new int[] { 0, 1, 2, 0, 0 },
   2633                 new int[] { 3 });
   2634         assertNotNull(states);
   2635         assertEquals(5, states.length);
   2636         assertEquals(0, states[0]);
   2637         assertEquals(1, states[1]);
   2638         assertEquals(2, states[2]);
   2639         assertEquals(3, states[3]);
   2640         assertEquals(0, states[4]);
   2641 
   2642         try {
   2643             view.mergeDrawableStatesWrapper(new int[] { 1, 2 }, new int[] { 3 });
   2644             fail("should throw IndexOutOfBoundsException");
   2645         } catch (IndexOutOfBoundsException e) {
   2646         }
   2647 
   2648         try {
   2649             view.mergeDrawableStatesWrapper(null, new int[] { 0 });
   2650             fail("should throw NullPointerException");
   2651         } catch (NullPointerException e) {
   2652         }
   2653 
   2654         try {
   2655             view.mergeDrawableStatesWrapper(new int [] { 0 }, null);
   2656             fail("should throw NullPointerException");
   2657         } catch (NullPointerException e) {
   2658         }
   2659     }
   2660 
   2661     @Test
   2662     public void testSaveAndRestoreHierarchyState() {
   2663         int viewId = R.id.mock_view;
   2664         MockView view = (MockView) mActivity.findViewById(viewId);
   2665         SparseArray<Parcelable> container = new SparseArray<>();
   2666         view.saveHierarchyState(container);
   2667         assertTrue(view.hasCalledDispatchSaveInstanceState());
   2668         assertTrue(view.hasCalledOnSaveInstanceState());
   2669         assertEquals(viewId, container.keyAt(0));
   2670 
   2671         view.reset();
   2672         container.put(R.id.mock_view, BaseSavedState.EMPTY_STATE);
   2673         view.restoreHierarchyState(container);
   2674         assertTrue(view.hasCalledDispatchRestoreInstanceState());
   2675         assertTrue(view.hasCalledOnRestoreInstanceState());
   2676         container.clear();
   2677         view.saveHierarchyState(container);
   2678         assertTrue(view.hasCalledDispatchSaveInstanceState());
   2679         assertTrue(view.hasCalledOnSaveInstanceState());
   2680         assertEquals(viewId, container.keyAt(0));
   2681 
   2682         container.clear();
   2683         container.put(viewId, new android.graphics.Rect());
   2684         try {
   2685             view.restoreHierarchyState(container);
   2686             fail("Parcelable state must be an AbsSaveState, should throw IllegalArgumentException");
   2687         } catch (IllegalArgumentException e) {
   2688             // expected
   2689         }
   2690 
   2691         try {
   2692             view.restoreHierarchyState(null);
   2693             fail("Cannot pass null to restoreHierarchyState(), should throw NullPointerException");
   2694         } catch (NullPointerException e) {
   2695             // expected
   2696         }
   2697 
   2698         try {
   2699             view.saveHierarchyState(null);
   2700             fail("Cannot pass null to saveHierarchyState(), should throw NullPointerException");
   2701         } catch (NullPointerException e) {
   2702             // expected
   2703         }
   2704     }
   2705 
   2706     @Test
   2707     public void testOnKeyDownOrUp() throws Throwable {
   2708         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   2709         mActivityRule.runOnUiThread(() -> {
   2710             view.setFocusable(true);
   2711             view.requestFocus();
   2712         });
   2713         mInstrumentation.waitForIdleSync();
   2714         assertTrue(view.isFocused());
   2715 
   2716         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
   2717         mInstrumentation.sendKeySync(event);
   2718         assertTrue(view.hasCalledOnKeyDown());
   2719 
   2720         event = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_0);
   2721         mInstrumentation.sendKeySync(event);
   2722         assertTrue(view.hasCalledOnKeyUp());
   2723 
   2724         view.reset();
   2725         assertTrue(view.isEnabled());
   2726         assertFalse(view.isClickable());
   2727         assertFalse(view.isPressed());
   2728         event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
   2729         mInstrumentation.sendKeySync(event);
   2730         assertFalse(view.isPressed());
   2731         assertTrue(view.hasCalledOnKeyDown());
   2732 
   2733         mActivityRule.runOnUiThread(() -> {
   2734             view.setEnabled(true);
   2735             view.setClickable(true);
   2736         });
   2737         view.reset();
   2738         View.OnClickListener listener = mock(View.OnClickListener.class);
   2739         view.setOnClickListener(listener);
   2740 
   2741         assertFalse(view.isPressed());
   2742         event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
   2743         mInstrumentation.sendKeySync(event);
   2744         assertTrue(view.isPressed());
   2745         assertTrue(view.hasCalledOnKeyDown());
   2746         event = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER);
   2747         mInstrumentation.sendKeySync(event);
   2748         assertFalse(view.isPressed());
   2749         assertTrue(view.hasCalledOnKeyUp());
   2750         verify(listener, times(1)).onClick(view);
   2751 
   2752         view.setPressed(false);
   2753         reset(listener);
   2754         view.reset();
   2755 
   2756         assertFalse(view.isPressed());
   2757         event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER);
   2758         mInstrumentation.sendKeySync(event);
   2759         assertTrue(view.isPressed());
   2760         assertTrue(view.hasCalledOnKeyDown());
   2761         event = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER);
   2762         mInstrumentation.sendKeySync(event);
   2763         assertFalse(view.isPressed());
   2764         assertTrue(view.hasCalledOnKeyUp());
   2765         verify(listener, times(1)).onClick(view);
   2766     }
   2767 
   2768     private void checkBounds(final ViewGroup viewGroup, final View view,
   2769             final CountDownLatch countDownLatch, final int left, final int top,
   2770             final int width, final int height) {
   2771         viewGroup.getViewTreeObserver().addOnPreDrawListener(
   2772                 new ViewTreeObserver.OnPreDrawListener() {
   2773             @Override
   2774             public boolean onPreDraw() {
   2775                 assertEquals(left, view.getLeft());
   2776                 assertEquals(top, view.getTop());
   2777                 assertEquals(width, view.getWidth());
   2778                 assertEquals(height, view.getHeight());
   2779                 countDownLatch.countDown();
   2780                 viewGroup.getViewTreeObserver().removeOnPreDrawListener(this);
   2781                 return true;
   2782             }
   2783         });
   2784     }
   2785 
   2786     @Test
   2787     public void testAddRemoveAffectsWrapContentLayout() throws Throwable {
   2788         final int childWidth = 100;
   2789         final int childHeight = 200;
   2790         final int parentHeight = 400;
   2791         final LinearLayout parent = new LinearLayout(mActivity);
   2792         ViewGroup.LayoutParams parentParams = new ViewGroup.LayoutParams(
   2793                 ViewGroup.LayoutParams.WRAP_CONTENT, parentHeight);
   2794         parent.setLayoutParams(parentParams);
   2795         final MockView child = new MockView(mActivity);
   2796         child.setBackgroundColor(Color.GREEN);
   2797         ViewGroup.LayoutParams childParams = new ViewGroup.LayoutParams(childWidth, childHeight);
   2798         child.setLayoutParams(childParams);
   2799         final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
   2800 
   2801         // Idea:
   2802         // Add the wrap_content parent view to the hierarchy (removing other views as they
   2803         // are not needed), test that parent is 0xparentHeight
   2804         // Add the child view to the parent, test that parent has same width as child
   2805         // Remove the child view from the parent, test that parent is 0xparentHeight
   2806         final CountDownLatch countDownLatch1 = new CountDownLatch(1);
   2807         mActivityRule.runOnUiThread(() -> {
   2808             viewGroup.removeAllViews();
   2809             viewGroup.addView(parent);
   2810             checkBounds(viewGroup, parent, countDownLatch1, 0, 0, 0, parentHeight);
   2811         });
   2812         countDownLatch1.await(500, TimeUnit.MILLISECONDS);
   2813 
   2814         final CountDownLatch countDownLatch2 = new CountDownLatch(1);
   2815         mActivityRule.runOnUiThread(() -> {
   2816             parent.addView(child);
   2817             checkBounds(viewGroup, parent, countDownLatch2, 0, 0, childWidth, parentHeight);
   2818         });
   2819         countDownLatch2.await(500, TimeUnit.MILLISECONDS);
   2820 
   2821         final CountDownLatch countDownLatch3 = new CountDownLatch(1);
   2822         mActivityRule.runOnUiThread(() -> {
   2823             parent.removeView(child);
   2824             checkBounds(viewGroup, parent, countDownLatch3, 0, 0, 0, parentHeight);
   2825         });
   2826         countDownLatch3.await(500, TimeUnit.MILLISECONDS);
   2827     }
   2828 
   2829     @UiThreadTest
   2830     @Test
   2831     public void testDispatchKeyEvent() {
   2832         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   2833         MockView mockView1 = new MockView(mActivity);
   2834         MockView mockView2 = new MockView(mActivity);
   2835         ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
   2836         viewGroup.addView(mockView1);
   2837         viewGroup.addView(mockView2);
   2838         view.setFocusable(true);
   2839         mockView1.setFocusable(true);
   2840         mockView2.setFocusable(true);
   2841 
   2842         assertFalse(view.hasCalledOnKeyDown());
   2843         assertFalse(mockView1.hasCalledOnKeyDown());
   2844         assertFalse(mockView2.hasCalledOnKeyDown());
   2845         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
   2846         assertFalse(view.dispatchKeyEvent(event));
   2847         assertTrue(view.hasCalledOnKeyDown());
   2848         assertFalse(mockView1.hasCalledOnKeyDown());
   2849         assertFalse(mockView2.hasCalledOnKeyDown());
   2850 
   2851         view.reset();
   2852         mockView1.reset();
   2853         mockView2.reset();
   2854         assertFalse(view.hasCalledOnKeyDown());
   2855         assertFalse(mockView1.hasCalledOnKeyDown());
   2856         assertFalse(mockView2.hasCalledOnKeyDown());
   2857         event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
   2858         assertFalse(mockView1.dispatchKeyEvent(event));
   2859         assertFalse(view.hasCalledOnKeyDown());
   2860         // issue 1695243
   2861         // When the view has NOT focus, it dispatches to itself, which disobey the javadoc.
   2862         assertTrue(mockView1.hasCalledOnKeyDown());
   2863         assertFalse(mockView2.hasCalledOnKeyDown());
   2864 
   2865         assertFalse(view.hasCalledOnKeyUp());
   2866         event = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_0);
   2867         assertFalse(view.dispatchKeyEvent(event));
   2868         assertTrue(view.hasCalledOnKeyUp());
   2869 
   2870         assertFalse(view.hasCalledOnKeyMultiple());
   2871         event = new KeyEvent(1, 2, KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_0, 2);
   2872         assertFalse(view.dispatchKeyEvent(event));
   2873         assertTrue(view.hasCalledOnKeyMultiple());
   2874 
   2875         try {
   2876             view.dispatchKeyEvent(null);
   2877             fail("should throw NullPointerException");
   2878         } catch (NullPointerException e) {
   2879             // expected
   2880         }
   2881 
   2882         view.reset();
   2883         event = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_0);
   2884         View.OnKeyListener listener = mock(View.OnKeyListener.class);
   2885         doReturn(true).when(listener).onKey(any(), anyInt(), any());
   2886         view.setOnKeyListener(listener);
   2887         verifyZeroInteractions(listener);
   2888         assertTrue(view.dispatchKeyEvent(event));
   2889         ArgumentCaptor<KeyEvent> keyEventCaptor = ArgumentCaptor.forClass(KeyEvent.class);
   2890         verify(listener, times(1)).onKey(eq(view), eq(KeyEvent.KEYCODE_0),
   2891                 keyEventCaptor.capture());
   2892         assertEquals(KeyEvent.ACTION_UP, keyEventCaptor.getValue().getAction());
   2893         assertEquals(KeyEvent.KEYCODE_0, keyEventCaptor.getValue().getKeyCode());
   2894         assertFalse(view.hasCalledOnKeyUp());
   2895     }
   2896 
   2897     @UiThreadTest
   2898     @Test
   2899     public void testDispatchTouchEvent() {
   2900         ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
   2901         MockView mockView1 = new MockView(mActivity);
   2902         MockView mockView2 = new MockView(mActivity);
   2903         viewGroup.addView(mockView1);
   2904         viewGroup.addView(mockView2);
   2905 
   2906         int[] xy = new int[2];
   2907         mockView1.getLocationOnScreen(xy);
   2908 
   2909         final int viewWidth = mockView1.getWidth();
   2910         final int viewHeight = mockView1.getHeight();
   2911         final float x = xy[0] + viewWidth / 2.0f;
   2912         final float y = xy[1] + viewHeight / 2.0f;
   2913 
   2914         long downTime = SystemClock.uptimeMillis();
   2915         long eventTime = SystemClock.uptimeMillis();
   2916         MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
   2917                 x, y, 0);
   2918 
   2919         assertFalse(mockView1.hasCalledOnTouchEvent());
   2920         assertFalse(mockView1.dispatchTouchEvent(event));
   2921         assertTrue(mockView1.hasCalledOnTouchEvent());
   2922 
   2923         assertFalse(mockView2.hasCalledOnTouchEvent());
   2924         assertFalse(mockView2.dispatchTouchEvent(event));
   2925         // issue 1695243
   2926         // it passes the touch screen motion event down to itself even if it is not the target view.
   2927         assertTrue(mockView2.hasCalledOnTouchEvent());
   2928 
   2929         mockView1.reset();
   2930         View.OnTouchListener listener = mock(View.OnTouchListener.class);
   2931         doReturn(true).when(listener).onTouch(any(), any());
   2932         mockView1.setOnTouchListener(listener);
   2933         verifyZeroInteractions(listener);
   2934         assertTrue(mockView1.dispatchTouchEvent(event));
   2935         verify(listener, times(1)).onTouch(mockView1, event);
   2936         assertFalse(mockView1.hasCalledOnTouchEvent());
   2937     }
   2938 
   2939     @Test
   2940     public void testInvalidate1() throws Throwable {
   2941         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   2942         assertTrue(view.hasCalledOnDraw());
   2943 
   2944         view.reset();
   2945         mActivityRule.runOnUiThread(view::invalidate);
   2946         mInstrumentation.waitForIdleSync();
   2947         PollingCheck.waitFor(view::hasCalledOnDraw);
   2948 
   2949         view.reset();
   2950         mActivityRule.runOnUiThread(() -> {
   2951             view.setVisibility(View.INVISIBLE);
   2952             view.invalidate();
   2953         });
   2954         mInstrumentation.waitForIdleSync();
   2955         assertFalse(view.hasCalledOnDraw());
   2956     }
   2957 
   2958     @Test
   2959     public void testInvalidate2() throws Throwable {
   2960         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   2961         assertTrue(view.hasCalledOnDraw());
   2962 
   2963         try {
   2964             view.invalidate(null);
   2965             fail("should throw NullPointerException");
   2966         } catch (NullPointerException e) {
   2967         }
   2968 
   2969         view.reset();
   2970         final Rect dirty = new Rect(view.getLeft() + 1, view.getTop() + 1,
   2971                 view.getLeft() + view.getWidth() / 2, view.getTop() + view.getHeight() / 2);
   2972         mActivityRule.runOnUiThread(() -> view.invalidate(dirty));
   2973         mInstrumentation.waitForIdleSync();
   2974         PollingCheck.waitFor(view::hasCalledOnDraw);
   2975 
   2976         view.reset();
   2977         mActivityRule.runOnUiThread(() -> {
   2978             view.setVisibility(View.INVISIBLE);
   2979             view.invalidate(dirty);
   2980         });
   2981         mInstrumentation.waitForIdleSync();
   2982         assertFalse(view.hasCalledOnDraw());
   2983     }
   2984 
   2985     @Test
   2986     public void testInvalidate3() throws Throwable {
   2987         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   2988         assertTrue(view.hasCalledOnDraw());
   2989 
   2990         view.reset();
   2991         final Rect dirty = new Rect(view.getLeft() + 1, view.getTop() + 1,
   2992                 view.getLeft() + view.getWidth() / 2, view.getTop() + view.getHeight() / 2);
   2993         mActivityRule.runOnUiThread(
   2994                 () -> view.invalidate(dirty.left, dirty.top, dirty.right, dirty.bottom));
   2995         mInstrumentation.waitForIdleSync();
   2996         PollingCheck.waitFor(view::hasCalledOnDraw);
   2997 
   2998         view.reset();
   2999         mActivityRule.runOnUiThread(() -> {
   3000             view.setVisibility(View.INVISIBLE);
   3001             view.invalidate(dirty.left, dirty.top, dirty.right, dirty.bottom);
   3002         });
   3003         mInstrumentation.waitForIdleSync();
   3004         assertFalse(view.hasCalledOnDraw());
   3005     }
   3006 
   3007     @Test
   3008     public void testInvalidateDrawable() throws Throwable {
   3009         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   3010         final Drawable d1 = mResources.getDrawable(R.drawable.scenery);
   3011         final Drawable d2 = mResources.getDrawable(R.drawable.pass);
   3012 
   3013         view.reset();
   3014         mActivityRule.runOnUiThread(() -> {
   3015             view.setBackgroundDrawable(d1);
   3016             view.invalidateDrawable(d1);
   3017         });
   3018         mInstrumentation.waitForIdleSync();
   3019         PollingCheck.waitFor(view::hasCalledOnDraw);
   3020 
   3021         view.reset();
   3022         mActivityRule.runOnUiThread(() -> view.invalidateDrawable(d2));
   3023         mInstrumentation.waitForIdleSync();
   3024         assertFalse(view.hasCalledOnDraw());
   3025 
   3026         MockView viewTestNull = new MockView(mActivity);
   3027         try {
   3028             viewTestNull.invalidateDrawable(null);
   3029             fail("should throw NullPointerException");
   3030         } catch (NullPointerException e) {
   3031         }
   3032     }
   3033 
   3034     @UiThreadTest
   3035     @Test
   3036     public void testOnFocusChanged() {
   3037         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   3038 
   3039         mActivity.findViewById(R.id.fit_windows).setFocusable(true);
   3040         view.setFocusable(true);
   3041         assertFalse(view.hasCalledOnFocusChanged());
   3042 
   3043         view.requestFocus();
   3044         assertTrue(view.hasCalledOnFocusChanged());
   3045 
   3046         view.reset();
   3047         view.clearFocus();
   3048         assertTrue(view.hasCalledOnFocusChanged());
   3049     }
   3050 
   3051     @UiThreadTest
   3052     @Test
   3053     public void testRestoreDefaultFocus() {
   3054         MockView view = new MockView(mActivity);
   3055         view.restoreDefaultFocus();
   3056         assertTrue(view.hasCalledRequestFocus());
   3057     }
   3058 
   3059     @Test
   3060     public void testDrawableState() {
   3061         MockView view = new MockView(mActivity);
   3062         view.setParent(mMockParent);
   3063 
   3064         assertFalse(view.hasCalledOnCreateDrawableState());
   3065         assertTrue(Arrays.equals(MockView.getEnabledStateSet(), view.getDrawableState()));
   3066         assertTrue(view.hasCalledOnCreateDrawableState());
   3067 
   3068         view.reset();
   3069         assertFalse(view.hasCalledOnCreateDrawableState());
   3070         assertTrue(Arrays.equals(MockView.getEnabledStateSet(), view.getDrawableState()));
   3071         assertFalse(view.hasCalledOnCreateDrawableState());
   3072 
   3073         view.reset();
   3074         assertFalse(view.hasCalledDrawableStateChanged());
   3075         view.setPressed(true);
   3076         assertTrue(view.hasCalledDrawableStateChanged());
   3077         assertTrue(Arrays.equals(MockView.getPressedEnabledStateSet(), view.getDrawableState()));
   3078         assertTrue(view.hasCalledOnCreateDrawableState());
   3079 
   3080         view.reset();
   3081         mMockParent.reset();
   3082         assertFalse(view.hasCalledDrawableStateChanged());
   3083         assertFalse(mMockParent.hasChildDrawableStateChanged());
   3084         view.refreshDrawableState();
   3085         assertTrue(view.hasCalledDrawableStateChanged());
   3086         assertTrue(mMockParent.hasChildDrawableStateChanged());
   3087         assertTrue(Arrays.equals(MockView.getPressedEnabledStateSet(), view.getDrawableState()));
   3088         assertTrue(view.hasCalledOnCreateDrawableState());
   3089     }
   3090 
   3091     @Test
   3092     public void testWindowFocusChanged() {
   3093         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   3094 
   3095         // Wait until the window has been focused.
   3096         PollingCheck.waitFor(TIMEOUT_DELTA, view::hasWindowFocus);
   3097 
   3098         PollingCheck.waitFor(view::hasCalledOnWindowFocusChanged);
   3099 
   3100         assertTrue(view.hasCalledOnWindowFocusChanged());
   3101         assertTrue(view.hasCalledDispatchWindowFocusChanged());
   3102 
   3103         view.reset();
   3104         assertFalse(view.hasCalledOnWindowFocusChanged());
   3105         assertFalse(view.hasCalledDispatchWindowFocusChanged());
   3106 
   3107         CtsActivity activity = mCtsActivityRule.launchActivity(null);
   3108 
   3109         // Wait until the window lost focus.
   3110         PollingCheck.waitFor(TIMEOUT_DELTA, () -> !view.hasWindowFocus());
   3111 
   3112         assertTrue(view.hasCalledOnWindowFocusChanged());
   3113         assertTrue(view.hasCalledDispatchWindowFocusChanged());
   3114 
   3115         activity.finish();
   3116     }
   3117 
   3118     @Test
   3119     public void testDraw() throws Throwable {
   3120         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   3121         mActivityRule.runOnUiThread(view::requestLayout);
   3122         mInstrumentation.waitForIdleSync();
   3123 
   3124         assertTrue(view.hasCalledOnDraw());
   3125         assertTrue(view.hasCalledDispatchDraw());
   3126     }
   3127 
   3128     @Test
   3129     public void testRequestFocusFromTouch() {
   3130         View view = new View(mActivity);
   3131         view.setFocusable(true);
   3132         assertFalse(view.isFocused());
   3133 
   3134         view.requestFocusFromTouch();
   3135         assertTrue(view.isFocused());
   3136 
   3137         view.requestFocusFromTouch();
   3138         assertTrue(view.isFocused());
   3139     }
   3140 
   3141     @Test
   3142     public void testRequestRectangleOnScreen1() {
   3143         MockView view = new MockView(mActivity);
   3144         Rect rectangle = new Rect(10, 10, 20, 30);
   3145         MockViewGroupParent parent = new MockViewGroupParent(mActivity);
   3146 
   3147         // parent is null
   3148         assertFalse(view.requestRectangleOnScreen(rectangle, true));
   3149         assertFalse(view.requestRectangleOnScreen(rectangle, false));
   3150         assertFalse(view.requestRectangleOnScreen(null, true));
   3151 
   3152         view.setParent(parent);
   3153         view.scrollTo(1, 2);
   3154         assertFalse(parent.hasRequestChildRectangleOnScreen());
   3155 
   3156         assertFalse(view.requestRectangleOnScreen(rectangle, true));
   3157         assertTrue(parent.hasRequestChildRectangleOnScreen());
   3158 
   3159         parent.reset();
   3160         view.scrollTo(11, 22);
   3161         assertFalse(parent.hasRequestChildRectangleOnScreen());
   3162 
   3163         assertFalse(view.requestRectangleOnScreen(rectangle, true));
   3164         assertTrue(parent.hasRequestChildRectangleOnScreen());
   3165 
   3166         try {
   3167             view.requestRectangleOnScreen(null, true);
   3168             fail("should throw NullPointerException");
   3169         } catch (NullPointerException e) {
   3170         }
   3171     }
   3172 
   3173     @Test
   3174     public void testRequestRectangleOnScreen2() {
   3175         MockView view = new MockView(mActivity);
   3176         Rect rectangle = new Rect();
   3177         MockViewGroupParent parent = new MockViewGroupParent(mActivity);
   3178 
   3179         MockViewGroupParent grandparent = new MockViewGroupParent(mActivity);
   3180 
   3181         // parent is null
   3182         assertFalse(view.requestRectangleOnScreen(rectangle));
   3183         assertFalse(view.requestRectangleOnScreen(null));
   3184         assertEquals(0, rectangle.left);
   3185         assertEquals(0, rectangle.top);
   3186         assertEquals(0, rectangle.right);
   3187         assertEquals(0, rectangle.bottom);
   3188 
   3189         parent.addView(view);
   3190         parent.scrollTo(1, 2);
   3191         grandparent.addView(parent);
   3192 
   3193         assertFalse(parent.hasRequestChildRectangleOnScreen());
   3194         assertFalse(grandparent.hasRequestChildRectangleOnScreen());
   3195 
   3196         assertFalse(view.requestRectangleOnScreen(rectangle));
   3197 
   3198         assertTrue(parent.hasRequestChildRectangleOnScreen());
   3199         assertTrue(grandparent.hasRequestChildRectangleOnScreen());
   3200 
   3201         // it is grand parent's responsibility to check parent's scroll offset
   3202         final Rect requestedRect = grandparent.getLastRequestedChildRectOnScreen();
   3203         assertEquals(0, requestedRect.left);
   3204         assertEquals(0, requestedRect.top);
   3205         assertEquals(0, requestedRect.right);
   3206         assertEquals(0, requestedRect.bottom);
   3207 
   3208         try {
   3209             view.requestRectangleOnScreen(null);
   3210             fail("should throw NullPointerException");
   3211         } catch (NullPointerException e) {
   3212         }
   3213     }
   3214 
   3215     @Test
   3216     public void testRequestRectangleOnScreen3() {
   3217         requestRectangleOnScreenTest(false);
   3218     }
   3219 
   3220     @Test
   3221     public void testRequestRectangleOnScreen4() {
   3222         requestRectangleOnScreenTest(true);
   3223     }
   3224 
   3225     @Test
   3226     public void testRequestRectangleOnScreen5() {
   3227         MockView child = new MockView(mActivity);
   3228 
   3229         MockViewGroupParent parent = new MockViewGroupParent(mActivity);
   3230         MockViewGroupParent grandParent = new MockViewGroupParent(mActivity);
   3231         parent.addView(child);
   3232         grandParent.addView(parent);
   3233 
   3234         child.layout(5, 6, 7, 9);
   3235         child.requestRectangleOnScreen(new Rect(10, 10, 12, 13));
   3236         assertEquals(new Rect(10, 10, 12, 13), parent.getLastRequestedChildRectOnScreen());
   3237         assertEquals(new Rect(15, 16, 17, 19), grandParent.getLastRequestedChildRectOnScreen());
   3238 
   3239         child.scrollBy(1, 2);
   3240         child.requestRectangleOnScreen(new Rect(10, 10, 12, 13));
   3241         assertEquals(new Rect(10, 10, 12, 13), parent.getLastRequestedChildRectOnScreen());
   3242         assertEquals(new Rect(14, 14, 16, 17), grandParent.getLastRequestedChildRectOnScreen());
   3243     }
   3244 
   3245     private void requestRectangleOnScreenTest(boolean scrollParent) {
   3246         MockView child = new MockView(mActivity);
   3247 
   3248         MockViewGroupParent parent = new MockViewGroupParent(mActivity);
   3249         MockViewGroupParent grandParent = new MockViewGroupParent(mActivity);
   3250         parent.addView(child);
   3251         grandParent.addView(parent);
   3252 
   3253         child.requestRectangleOnScreen(new Rect(10, 10, 12, 13));
   3254         assertEquals(new Rect(10, 10, 12, 13), parent.getLastRequestedChildRectOnScreen());
   3255         assertEquals(new Rect(10, 10, 12, 13), grandParent.getLastRequestedChildRectOnScreen());
   3256 
   3257         child.scrollBy(1, 2);
   3258         if (scrollParent) {
   3259             // should not affect anything
   3260             parent.scrollBy(25, 30);
   3261             parent.layout(3, 5, 7, 9);
   3262         }
   3263         child.requestRectangleOnScreen(new Rect(10, 10, 12, 13));
   3264         assertEquals(new Rect(10, 10, 12, 13), parent.getLastRequestedChildRectOnScreen());
   3265         assertEquals(new Rect(9, 8, 11, 11), grandParent.getLastRequestedChildRectOnScreen());
   3266     }
   3267 
   3268     @Test
   3269     public void testRequestRectangleOnScreenWithScale() {
   3270         // scale should not affect the rectangle
   3271         MockView child = new MockView(mActivity);
   3272         child.setScaleX(2);
   3273         child.setScaleX(3);
   3274         MockViewGroupParent parent = new MockViewGroupParent(mActivity);
   3275         MockViewGroupParent grandParent = new MockViewGroupParent(mActivity);
   3276         parent.addView(child);
   3277         grandParent.addView(parent);
   3278         child.requestRectangleOnScreen(new Rect(10, 10, 12, 13));
   3279         assertEquals(new Rect(10, 10, 12, 13), parent.getLastRequestedChildRectOnScreen());
   3280         assertEquals(new Rect(10, 10, 12, 13), grandParent.getLastRequestedChildRectOnScreen());
   3281     }
   3282 
   3283     /**
   3284      * For the duration of the tap timeout we are in a 'prepressed' state
   3285      * to differentiate between taps and touch scrolls.
   3286      * Wait at least this long before testing if the view is pressed
   3287      * by calling this function.
   3288      */
   3289     private void waitPrepressedTimeout() {
   3290         try {
   3291             Thread.sleep(ViewConfiguration.getTapTimeout() + 10);
   3292         } catch (InterruptedException e) {
   3293             Log.e(LOG_TAG, "waitPrepressedTimeout() interrupted! Test may fail!", e);
   3294         }
   3295         mInstrumentation.waitForIdleSync();
   3296     }
   3297 
   3298     @Test
   3299     public void testOnTouchEvent() throws Throwable {
   3300         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   3301 
   3302         assertTrue(view.isEnabled());
   3303         assertFalse(view.isClickable());
   3304         assertFalse(view.isLongClickable());
   3305 
   3306         CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, view);
   3307         assertTrue(view.hasCalledOnTouchEvent());
   3308 
   3309         mActivityRule.runOnUiThread(() -> {
   3310             view.setEnabled(true);
   3311             view.setClickable(true);
   3312             view.setLongClickable(true);
   3313         });
   3314         mInstrumentation.waitForIdleSync();
   3315         assertTrue(view.isEnabled());
   3316         assertTrue(view.isClickable());
   3317         assertTrue(view.isLongClickable());
   3318 
   3319         // MotionEvent.ACTION_DOWN
   3320         int[] xy = new int[2];
   3321         view.getLocationOnScreen(xy);
   3322 
   3323         final int viewWidth = view.getWidth();
   3324         final int viewHeight = view.getHeight();
   3325         float x = xy[0] + viewWidth / 2.0f;
   3326         float y = xy[1] + viewHeight / 2.0f;
   3327 
   3328         long downTime = SystemClock.uptimeMillis();
   3329         long eventTime = SystemClock.uptimeMillis();
   3330         MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN,
   3331                 x, y, 0);
   3332         assertFalse(view.isPressed());
   3333         mInstrumentation.sendPointerSync(event);
   3334         waitPrepressedTimeout();
   3335         assertTrue(view.hasCalledOnTouchEvent());
   3336         assertTrue(view.isPressed());
   3337 
   3338         // MotionEvent.ACTION_MOVE
   3339         // move out of the bound.
   3340         view.reset();
   3341         downTime = SystemClock.uptimeMillis();
   3342         eventTime = SystemClock.uptimeMillis();
   3343         int slop = ViewConfiguration.get(mActivity).getScaledTouchSlop();
   3344         x = xy[0] + viewWidth + slop;
   3345         y = xy[1] + viewHeight + slop;
   3346         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
   3347         mInstrumentation.sendPointerSync(event);
   3348         assertTrue(view.hasCalledOnTouchEvent());
   3349         assertFalse(view.isPressed());
   3350 
   3351         // move into view
   3352         view.reset();
   3353         downTime = SystemClock.uptimeMillis();
   3354         eventTime = SystemClock.uptimeMillis();
   3355         x = xy[0] + viewWidth - 1;
   3356         y = xy[1] + viewHeight - 1;
   3357         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
   3358         mInstrumentation.sendPointerSync(event);
   3359         waitPrepressedTimeout();
   3360         assertTrue(view.hasCalledOnTouchEvent());
   3361         assertFalse(view.isPressed());
   3362 
   3363         // MotionEvent.ACTION_UP
   3364         View.OnClickListener listener = mock(View.OnClickListener.class);
   3365         view.setOnClickListener(listener);
   3366         view.reset();
   3367         downTime = SystemClock.uptimeMillis();
   3368         eventTime = SystemClock.uptimeMillis();
   3369         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
   3370         mInstrumentation.sendPointerSync(event);
   3371         assertTrue(view.hasCalledOnTouchEvent());
   3372         verifyZeroInteractions(listener);
   3373 
   3374         view.reset();
   3375         x = xy[0] + viewWidth / 2.0f;
   3376         y = xy[1] + viewHeight / 2.0f;
   3377         downTime = SystemClock.uptimeMillis();
   3378         eventTime = SystemClock.uptimeMillis();
   3379         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
   3380         mInstrumentation.sendPointerSync(event);
   3381         assertTrue(view.hasCalledOnTouchEvent());
   3382 
   3383         // MotionEvent.ACTION_CANCEL
   3384         view.reset();
   3385         reset(listener);
   3386         downTime = SystemClock.uptimeMillis();
   3387         eventTime = SystemClock.uptimeMillis();
   3388         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_CANCEL, x, y, 0);
   3389         mInstrumentation.sendPointerSync(event);
   3390         assertTrue(view.hasCalledOnTouchEvent());
   3391         assertFalse(view.isPressed());
   3392         verifyZeroInteractions(listener);
   3393     }
   3394 
   3395     @Test
   3396     public void testBringToFront() {
   3397         MockView view = new MockView(mActivity);
   3398         view.setParent(mMockParent);
   3399 
   3400         assertFalse(mMockParent.hasBroughtChildToFront());
   3401         view.bringToFront();
   3402         assertTrue(mMockParent.hasBroughtChildToFront());
   3403     }
   3404 
   3405     @Test
   3406     public void testGetApplicationWindowToken() {
   3407         View view = new View(mActivity);
   3408         // mAttachInfo is null
   3409         assertNull(view.getApplicationWindowToken());
   3410 
   3411         // mAttachInfo is not null
   3412         view = mActivity.findViewById(R.id.fit_windows);
   3413         assertNotNull(view.getApplicationWindowToken());
   3414     }
   3415 
   3416     @Test
   3417     public void testGetBottomPaddingOffset() {
   3418         MockView view = new MockView(mActivity);
   3419         assertEquals(0, view.getBottomPaddingOffset());
   3420     }
   3421 
   3422     @Test
   3423     public void testGetLeftPaddingOffset() {
   3424         MockView view = new MockView(mActivity);
   3425         assertEquals(0, view.getLeftPaddingOffset());
   3426     }
   3427 
   3428     @Test
   3429     public void testGetRightPaddingOffset() {
   3430         MockView view = new MockView(mActivity);
   3431         assertEquals(0, view.getRightPaddingOffset());
   3432     }
   3433 
   3434     @Test
   3435     public void testGetTopPaddingOffset() {
   3436         MockView view = new MockView(mActivity);
   3437         assertEquals(0, view.getTopPaddingOffset());
   3438     }
   3439 
   3440     @Test
   3441     public void testIsPaddingOffsetRequired() {
   3442         MockView view = new MockView(mActivity);
   3443         assertFalse(view.isPaddingOffsetRequired());
   3444     }
   3445 
   3446     @UiThreadTest
   3447     @Test
   3448     public void testPadding() {
   3449         MockView view = (MockView) mActivity.findViewById(R.id.mock_view_padding_full);
   3450         Drawable background = view.getBackground();
   3451         Rect backgroundPadding = new Rect();
   3452         background.getPadding(backgroundPadding);
   3453 
   3454         // There is some background with a non null padding
   3455         assertNotNull(background);
   3456         assertTrue(backgroundPadding.left != 0);
   3457         assertTrue(backgroundPadding.right != 0);
   3458         assertTrue(backgroundPadding.top != 0);
   3459         assertTrue(backgroundPadding.bottom != 0);
   3460 
   3461         // The XML defines android:padding="0dp" and that should be the resulting padding
   3462         assertEquals(0, view.getPaddingLeft());
   3463         assertEquals(0, view.getPaddingTop());
   3464         assertEquals(0, view.getPaddingRight());
   3465         assertEquals(0, view.getPaddingBottom());
   3466 
   3467         // LEFT case
   3468         view = (MockView) mActivity.findViewById(R.id.mock_view_padding_left);
   3469         background = view.getBackground();
   3470         backgroundPadding = new Rect();
   3471         background.getPadding(backgroundPadding);
   3472 
   3473         // There is some background with a non null padding
   3474         assertNotNull(background);
   3475         assertTrue(backgroundPadding.left != 0);
   3476         assertTrue(backgroundPadding.right != 0);
   3477         assertTrue(backgroundPadding.top != 0);
   3478         assertTrue(backgroundPadding.bottom != 0);
   3479 
   3480         // The XML defines android:paddingLeft="0dp" and that should be the resulting padding
   3481         assertEquals(0, view.getPaddingLeft());
   3482         assertEquals(backgroundPadding.top, view.getPaddingTop());
   3483         assertEquals(backgroundPadding.right, view.getPaddingRight());
   3484         assertEquals(backgroundPadding.bottom, view.getPaddingBottom());
   3485 
   3486         // RIGHT case
   3487         view = (MockView) mActivity.findViewById(R.id.mock_view_padding_right);
   3488         background = view.getBackground();
   3489         backgroundPadding = new Rect();
   3490         background.getPadding(backgroundPadding);
   3491 
   3492         // There is some background with a non null padding
   3493         assertNotNull(background);
   3494         assertTrue(backgroundPadding.left != 0);
   3495         assertTrue(backgroundPadding.right != 0);
   3496         assertTrue(backgroundPadding.top != 0);
   3497         assertTrue(backgroundPadding.bottom != 0);
   3498 
   3499         // The XML defines android:paddingRight="0dp" and that should be the resulting padding
   3500         assertEquals(backgroundPadding.left, view.getPaddingLeft());
   3501         assertEquals(backgroundPadding.top, view.getPaddingTop());
   3502         assertEquals(0, view.getPaddingRight());
   3503         assertEquals(backgroundPadding.bottom, view.getPaddingBottom());
   3504 
   3505         // TOP case
   3506         view = (MockView) mActivity.findViewById(R.id.mock_view_padding_top);
   3507         background = view.getBackground();
   3508         backgroundPadding = new Rect();
   3509         background.getPadding(backgroundPadding);
   3510 
   3511         // There is some background with a non null padding
   3512         assertNotNull(background);
   3513         assertTrue(backgroundPadding.left != 0);
   3514         assertTrue(backgroundPadding.right != 0);
   3515         assertTrue(backgroundPadding.top != 0);
   3516         assertTrue(backgroundPadding.bottom != 0);
   3517 
   3518         // The XML defines android:paddingTop="0dp" and that should be the resulting padding
   3519         assertEquals(backgroundPadding.left, view.getPaddingLeft());
   3520         assertEquals(0, view.getPaddingTop());
   3521         assertEquals(backgroundPadding.right, view.getPaddingRight());
   3522         assertEquals(backgroundPadding.bottom, view.getPaddingBottom());
   3523 
   3524         // BOTTOM case
   3525         view = (MockView) mActivity.findViewById(R.id.mock_view_padding_bottom);
   3526         background = view.getBackground();
   3527         backgroundPadding = new Rect();
   3528         background.getPadding(backgroundPadding);
   3529 
   3530         // There is some background with a non null padding
   3531         assertNotNull(background);
   3532         assertTrue(backgroundPadding.left != 0);
   3533         assertTrue(backgroundPadding.right != 0);
   3534         assertTrue(backgroundPadding.top != 0);
   3535         assertTrue(backgroundPadding.bottom != 0);
   3536 
   3537         // The XML defines android:paddingBottom="0dp" and that should be the resulting padding
   3538         assertEquals(backgroundPadding.left, view.getPaddingLeft());
   3539         assertEquals(backgroundPadding.top, view.getPaddingTop());
   3540         assertEquals(backgroundPadding.right, view.getPaddingRight());
   3541         assertEquals(0, view.getPaddingBottom());
   3542 
   3543         // Case for interleaved background/padding changes
   3544         view = (MockView) mActivity.findViewById(R.id.mock_view_padding_runtime_updated);
   3545         background = view.getBackground();
   3546         backgroundPadding = new Rect();
   3547         background.getPadding(backgroundPadding);
   3548 
   3549         // There is some background with a null padding
   3550         assertNotNull(background);
   3551         assertTrue(backgroundPadding.left == 0);
   3552         assertTrue(backgroundPadding.right == 0);
   3553         assertTrue(backgroundPadding.top == 0);
   3554         assertTrue(backgroundPadding.bottom == 0);
   3555 
   3556         final int paddingLeft = view.getPaddingLeft();
   3557         final int paddingRight = view.getPaddingRight();
   3558         final int paddingTop = view.getPaddingTop();
   3559         final int paddingBottom = view.getPaddingBottom();
   3560         assertEquals(8, paddingLeft);
   3561         assertEquals(0, paddingTop);
   3562         assertEquals(8, paddingRight);
   3563         assertEquals(0, paddingBottom);
   3564 
   3565         // Manipulate background and padding
   3566         background.setState(view.getDrawableState());
   3567         background.jumpToCurrentState();
   3568         view.setBackground(background);
   3569         view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
   3570 
   3571         assertEquals(8, view.getPaddingLeft());
   3572         assertEquals(0, view.getPaddingTop());
   3573         assertEquals(8, view.getPaddingRight());
   3574         assertEquals(0, view.getPaddingBottom());
   3575     }
   3576 
   3577     @Test
   3578     public void testGetWindowVisibleDisplayFrame() {
   3579         Rect outRect = new Rect();
   3580         View view = new View(mActivity);
   3581         // mAttachInfo is null
   3582         DisplayManager dm = (DisplayManager) mActivity.getApplicationContext().getSystemService(
   3583                 Context.DISPLAY_SERVICE);
   3584         Display d = dm.getDisplay(Display.DEFAULT_DISPLAY);
   3585         view.getWindowVisibleDisplayFrame(outRect);
   3586         assertEquals(0, outRect.left);
   3587         assertEquals(0, outRect.top);
   3588         assertEquals(d.getWidth(), outRect.right);
   3589         assertEquals(d.getHeight(), outRect.bottom);
   3590 
   3591         // mAttachInfo is not null
   3592         outRect = new Rect();
   3593         view = mActivity.findViewById(R.id.fit_windows);
   3594         // it's implementation detail
   3595         view.getWindowVisibleDisplayFrame(outRect);
   3596     }
   3597 
   3598     @Test
   3599     public void testSetScrollContainer() throws Throwable {
   3600         final MockView mockView = (MockView) mActivity.findViewById(R.id.mock_view);
   3601         final MockView scrollView = (MockView) mActivity.findViewById(R.id.scroll_view);
   3602         Bitmap bitmap = Bitmap.createBitmap(200, 300, Bitmap.Config.RGB_565);
   3603         final BitmapDrawable d = new BitmapDrawable(bitmap);
   3604         final InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(
   3605                 Context.INPUT_METHOD_SERVICE);
   3606         final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(300, 500);
   3607         mActivityRule.runOnUiThread(() -> {
   3608             mockView.setBackgroundDrawable(d);
   3609             mockView.setHorizontalFadingEdgeEnabled(true);
   3610             mockView.setVerticalFadingEdgeEnabled(true);
   3611             mockView.setLayoutParams(layoutParams);
   3612             scrollView.setLayoutParams(layoutParams);
   3613 
   3614             mockView.setFocusable(true);
   3615             mockView.requestFocus();
   3616             mockView.setScrollContainer(true);
   3617             scrollView.setScrollContainer(false);
   3618             imm.showSoftInput(mockView, 0);
   3619         });
   3620         mInstrumentation.waitForIdleSync();
   3621 
   3622         // FIXME: why the size of view doesn't change?
   3623 
   3624         mActivityRule.runOnUiThread(
   3625                 () -> imm.hideSoftInputFromInputMethod(mockView.getWindowToken(), 0));
   3626         mInstrumentation.waitForIdleSync();
   3627     }
   3628 
   3629     @Test
   3630     public void testTouchMode() throws Throwable {
   3631         final MockView mockView = (MockView) mActivity.findViewById(R.id.mock_view);
   3632         final View fitWindowsView = mActivity.findViewById(R.id.fit_windows);
   3633         mActivityRule.runOnUiThread(() -> {
   3634             mockView.setFocusableInTouchMode(true);
   3635             fitWindowsView.setFocusable(true);
   3636             fitWindowsView.requestFocus();
   3637         });
   3638         mInstrumentation.waitForIdleSync();
   3639         assertTrue(mockView.isFocusableInTouchMode());
   3640         assertFalse(fitWindowsView.isFocusableInTouchMode());
   3641         assertTrue(mockView.isFocusable());
   3642         assertTrue(fitWindowsView.isFocusable());
   3643         assertFalse(mockView.isFocused());
   3644         assertTrue(fitWindowsView.isFocused());
   3645         assertFalse(mockView.isInTouchMode());
   3646         assertFalse(fitWindowsView.isInTouchMode());
   3647 
   3648         CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mockView);
   3649         assertFalse(fitWindowsView.isFocused());
   3650         assertFalse(mockView.isFocused());
   3651         mActivityRule.runOnUiThread(mockView::requestFocus);
   3652         mInstrumentation.waitForIdleSync();
   3653         assertTrue(mockView.isFocused());
   3654         mActivityRule.runOnUiThread(fitWindowsView::requestFocus);
   3655         mInstrumentation.waitForIdleSync();
   3656         assertFalse(fitWindowsView.isFocused());
   3657         assertTrue(mockView.isInTouchMode());
   3658         assertTrue(fitWindowsView.isInTouchMode());
   3659 
   3660         KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
   3661         mInstrumentation.sendKeySync(keyEvent);
   3662         assertTrue(mockView.isFocused());
   3663         assertFalse(fitWindowsView.isFocused());
   3664         mActivityRule.runOnUiThread(fitWindowsView::requestFocus);
   3665         mInstrumentation.waitForIdleSync();
   3666         assertFalse(mockView.isFocused());
   3667         assertTrue(fitWindowsView.isFocused());
   3668         assertFalse(mockView.isInTouchMode());
   3669         assertFalse(fitWindowsView.isInTouchMode());
   3670 
   3671         // Mouse events should not trigger touch mode.
   3672         final MotionEvent event =
   3673                 CtsMouseUtil.obtainMouseEvent(MotionEvent.ACTION_SCROLL, mockView, 0, 0);
   3674         mInstrumentation.sendPointerSync(event);
   3675         assertFalse(fitWindowsView.isInTouchMode());
   3676 
   3677         event.setAction(MotionEvent.ACTION_DOWN);
   3678         mInstrumentation.sendPointerSync(event);
   3679         assertFalse(fitWindowsView.isInTouchMode());
   3680 
   3681         // Stylus events should not trigger touch mode.
   3682         event.setSource(InputDevice.SOURCE_STYLUS);
   3683         mInstrumentation.sendPointerSync(event);
   3684         assertFalse(fitWindowsView.isInTouchMode());
   3685 
   3686         CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mockView);
   3687         assertTrue(fitWindowsView.isInTouchMode());
   3688 
   3689         event.setSource(InputDevice.SOURCE_MOUSE);
   3690         event.setAction(MotionEvent.ACTION_DOWN);
   3691         mInstrumentation.sendPointerSync(event);
   3692         assertFalse(fitWindowsView.isInTouchMode());
   3693     }
   3694 
   3695     @UiThreadTest
   3696     @Test
   3697     public void testScrollbarStyle() {
   3698         MockView view = (MockView) mActivity.findViewById(R.id.scroll_view);
   3699         Bitmap bitmap = Bitmap.createBitmap(200, 300, Bitmap.Config.RGB_565);
   3700         BitmapDrawable d = new BitmapDrawable(bitmap);
   3701         view.setBackgroundDrawable(d);
   3702         view.setHorizontalFadingEdgeEnabled(true);
   3703         view.setVerticalFadingEdgeEnabled(true);
   3704 
   3705         assertTrue(view.isHorizontalScrollBarEnabled());
   3706         assertTrue(view.isVerticalScrollBarEnabled());
   3707         int verticalScrollBarWidth = view.getVerticalScrollbarWidth();
   3708         int horizontalScrollBarHeight = view.getHorizontalScrollbarHeight();
   3709         assertTrue(verticalScrollBarWidth > 0);
   3710         assertTrue(horizontalScrollBarHeight > 0);
   3711         assertEquals(0, view.getPaddingRight());
   3712         assertEquals(0, view.getPaddingBottom());
   3713 
   3714         view.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
   3715         assertEquals(View.SCROLLBARS_INSIDE_INSET, view.getScrollBarStyle());
   3716         assertEquals(verticalScrollBarWidth, view.getPaddingRight());
   3717         assertEquals(horizontalScrollBarHeight, view.getPaddingBottom());
   3718 
   3719         view.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);
   3720         assertEquals(View.SCROLLBARS_OUTSIDE_OVERLAY, view.getScrollBarStyle());
   3721         assertEquals(0, view.getPaddingRight());
   3722         assertEquals(0, view.getPaddingBottom());
   3723 
   3724         view.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_INSET);
   3725         assertEquals(View.SCROLLBARS_OUTSIDE_INSET, view.getScrollBarStyle());
   3726         assertEquals(verticalScrollBarWidth, view.getPaddingRight());
   3727         assertEquals(horizontalScrollBarHeight, view.getPaddingBottom());
   3728 
   3729         // TODO: how to get the position of the Scrollbar to assert it is inside or outside.
   3730     }
   3731 
   3732     @UiThreadTest
   3733     @Test
   3734     public void testScrollFading() {
   3735         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   3736         Bitmap bitmap = Bitmap.createBitmap(200, 300, Bitmap.Config.RGB_565);
   3737         BitmapDrawable d = new BitmapDrawable(bitmap);
   3738         view.setBackgroundDrawable(d);
   3739 
   3740         assertFalse(view.isHorizontalFadingEdgeEnabled());
   3741         assertFalse(view.isVerticalFadingEdgeEnabled());
   3742         assertEquals(0, view.getHorizontalFadingEdgeLength());
   3743         assertEquals(0, view.getVerticalFadingEdgeLength());
   3744 
   3745         view.setHorizontalFadingEdgeEnabled(true);
   3746         view.setVerticalFadingEdgeEnabled(true);
   3747         assertTrue(view.isHorizontalFadingEdgeEnabled());
   3748         assertTrue(view.isVerticalFadingEdgeEnabled());
   3749         assertTrue(view.getHorizontalFadingEdgeLength() > 0);
   3750         assertTrue(view.getVerticalFadingEdgeLength() > 0);
   3751 
   3752         final int fadingLength = 20;
   3753         view.setFadingEdgeLength(fadingLength);
   3754         assertEquals(fadingLength, view.getHorizontalFadingEdgeLength());
   3755         assertEquals(fadingLength, view.getVerticalFadingEdgeLength());
   3756     }
   3757 
   3758     @UiThreadTest
   3759     @Test
   3760     public void testScrolling() {
   3761         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   3762         view.reset();
   3763         assertEquals(0, view.getScrollX());
   3764         assertEquals(0, view.getScrollY());
   3765         assertFalse(view.hasCalledOnScrollChanged());
   3766 
   3767         view.scrollTo(0, 0);
   3768         assertEquals(0, view.getScrollX());
   3769         assertEquals(0, view.getScrollY());
   3770         assertFalse(view.hasCalledOnScrollChanged());
   3771 
   3772         view.scrollBy(0, 0);
   3773         assertEquals(0, view.getScrollX());
   3774         assertEquals(0, view.getScrollY());
   3775         assertFalse(view.hasCalledOnScrollChanged());
   3776 
   3777         view.scrollTo(10, 100);
   3778         assertEquals(10, view.getScrollX());
   3779         assertEquals(100, view.getScrollY());
   3780         assertTrue(view.hasCalledOnScrollChanged());
   3781 
   3782         view.reset();
   3783         assertFalse(view.hasCalledOnScrollChanged());
   3784         view.scrollBy(-10, -100);
   3785         assertEquals(0, view.getScrollX());
   3786         assertEquals(0, view.getScrollY());
   3787         assertTrue(view.hasCalledOnScrollChanged());
   3788 
   3789         view.reset();
   3790         assertFalse(view.hasCalledOnScrollChanged());
   3791         view.scrollTo(-1, -2);
   3792         assertEquals(-1, view.getScrollX());
   3793         assertEquals(-2, view.getScrollY());
   3794         assertTrue(view.hasCalledOnScrollChanged());
   3795     }
   3796 
   3797     @Test
   3798     public void testInitializeScrollbarsAndFadingEdge() {
   3799         MockView view = (MockView) mActivity.findViewById(R.id.scroll_view);
   3800 
   3801         assertTrue(view.isHorizontalScrollBarEnabled());
   3802         assertTrue(view.isVerticalScrollBarEnabled());
   3803         assertFalse(view.isHorizontalFadingEdgeEnabled());
   3804         assertFalse(view.isVerticalFadingEdgeEnabled());
   3805 
   3806         view = (MockView) mActivity.findViewById(R.id.scroll_view_2);
   3807         final int fadingEdgeLength = 20;
   3808 
   3809         assertTrue(view.isHorizontalScrollBarEnabled());
   3810         assertTrue(view.isVerticalScrollBarEnabled());
   3811         assertTrue(view.isHorizontalFadingEdgeEnabled());
   3812         assertTrue(view.isVerticalFadingEdgeEnabled());
   3813         assertEquals(fadingEdgeLength, view.getHorizontalFadingEdgeLength());
   3814         assertEquals(fadingEdgeLength, view.getVerticalFadingEdgeLength());
   3815     }
   3816 
   3817     @UiThreadTest
   3818     @Test
   3819     public void testScrollIndicators() {
   3820         MockView view = (MockView) mActivity.findViewById(R.id.scroll_view);
   3821 
   3822         assertEquals("Set indicators match those specified in XML",
   3823                 View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM,
   3824                 view.getScrollIndicators());
   3825 
   3826         view.setScrollIndicators(0);
   3827         assertEquals("Cleared indicators", 0, view.getScrollIndicators());
   3828 
   3829         view.setScrollIndicators(View.SCROLL_INDICATOR_START | View.SCROLL_INDICATOR_RIGHT);
   3830         assertEquals("Set start and right indicators",
   3831                 View.SCROLL_INDICATOR_START | View.SCROLL_INDICATOR_RIGHT,
   3832                 view.getScrollIndicators());
   3833 
   3834     }
   3835 
   3836     @Test
   3837     public void testScrollbarSize() {
   3838         final int configScrollbarSize = ViewConfiguration.get(mActivity).getScaledScrollBarSize();
   3839         final int customScrollbarSize = configScrollbarSize * 2;
   3840 
   3841         // No explicit scrollbarSize or custom drawables, ViewConfiguration applies.
   3842         final MockView view = (MockView) mActivity.findViewById(R.id.scroll_view);
   3843         assertEquals(configScrollbarSize, view.getScrollBarSize());
   3844         assertEquals(configScrollbarSize, view.getVerticalScrollbarWidth());
   3845         assertEquals(configScrollbarSize, view.getHorizontalScrollbarHeight());
   3846 
   3847         // No custom drawables, explicit scrollbarSize takes precedence.
   3848         final MockView view2 = (MockView) mActivity.findViewById(R.id.scroll_view_2);
   3849         view2.setScrollBarSize(customScrollbarSize);
   3850         assertEquals(customScrollbarSize, view2.getScrollBarSize());
   3851         assertEquals(customScrollbarSize, view2.getVerticalScrollbarWidth());
   3852         assertEquals(customScrollbarSize, view2.getHorizontalScrollbarHeight());
   3853 
   3854         // Custom drawables with no intrinsic size, ViewConfiguration applies.
   3855         final MockView view3 = (MockView) mActivity.findViewById(R.id.scroll_view_3);
   3856         assertEquals(configScrollbarSize, view3.getVerticalScrollbarWidth());
   3857         assertEquals(configScrollbarSize, view3.getHorizontalScrollbarHeight());
   3858         // Explicit scrollbarSize takes precedence.
   3859         view3.setScrollBarSize(customScrollbarSize);
   3860         assertEquals(view3.getScrollBarSize(), view3.getVerticalScrollbarWidth());
   3861         assertEquals(view3.getScrollBarSize(), view3.getHorizontalScrollbarHeight());
   3862 
   3863         // Custom thumb drawables with intrinsic sizes define the scrollbars' dimensions.
   3864         final MockView view4 = (MockView) mActivity.findViewById(R.id.scroll_view_4);
   3865         final Resources res = mActivity.getResources();
   3866         final int thumbWidth = res.getDimensionPixelSize(R.dimen.scrollbar_thumb_width);
   3867         final int thumbHeight = res.getDimensionPixelSize(R.dimen.scrollbar_thumb_height);
   3868         assertEquals(thumbWidth, view4.getVerticalScrollbarWidth());
   3869         assertEquals(thumbHeight, view4.getHorizontalScrollbarHeight());
   3870         // Explicit scrollbarSize has no effect.
   3871         view4.setScrollBarSize(customScrollbarSize);
   3872         assertEquals(thumbWidth, view4.getVerticalScrollbarWidth());
   3873         assertEquals(thumbHeight, view4.getHorizontalScrollbarHeight());
   3874 
   3875         // Custom thumb and track drawables with intrinsic sizes. Track size take precedence.
   3876         final MockView view5 = (MockView) mActivity.findViewById(R.id.scroll_view_5);
   3877         final int trackWidth = res.getDimensionPixelSize(R.dimen.scrollbar_track_width);
   3878         final int trackHeight = res.getDimensionPixelSize(R.dimen.scrollbar_track_height);
   3879         assertEquals(trackWidth, view5.getVerticalScrollbarWidth());
   3880         assertEquals(trackHeight, view5.getHorizontalScrollbarHeight());
   3881         // Explicit scrollbarSize has no effect.
   3882         view5.setScrollBarSize(customScrollbarSize);
   3883         assertEquals(trackWidth, view5.getVerticalScrollbarWidth());
   3884         assertEquals(trackHeight, view5.getHorizontalScrollbarHeight());
   3885 
   3886         // Custom thumb and track, track with no intrinsic size, ViewConfiguration applies
   3887         // regardless of the thumb drawable dimensions.
   3888         final MockView view6 = (MockView) mActivity.findViewById(R.id.scroll_view_6);
   3889         assertEquals(configScrollbarSize, view6.getVerticalScrollbarWidth());
   3890         assertEquals(configScrollbarSize, view6.getHorizontalScrollbarHeight());
   3891         // Explicit scrollbarSize takes precedence.
   3892         view6.setScrollBarSize(customScrollbarSize);
   3893         assertEquals(customScrollbarSize, view6.getVerticalScrollbarWidth());
   3894         assertEquals(customScrollbarSize, view6.getHorizontalScrollbarHeight());
   3895     }
   3896 
   3897     @Test
   3898     public void testOnStartAndFinishTemporaryDetach() throws Throwable {
   3899         final AtomicBoolean exitedDispatchStartTemporaryDetach = new AtomicBoolean(false);
   3900         final AtomicBoolean exitedDispatchFinishTemporaryDetach = new AtomicBoolean(false);
   3901 
   3902         final View view = new View(mActivity) {
   3903             private boolean mEnteredDispatchStartTemporaryDetach = false;
   3904             private boolean mExitedDispatchStartTemporaryDetach = false;
   3905             private boolean mEnteredDispatchFinishTemporaryDetach = false;
   3906             private boolean mExitedDispatchFinishTemporaryDetach = false;
   3907 
   3908             private boolean mCalledOnStartTemporaryDetach = false;
   3909             private boolean mCalledOnFinishTemporaryDetach = false;
   3910 
   3911             @Override
   3912             public void dispatchStartTemporaryDetach() {
   3913                 assertFalse(mEnteredDispatchStartTemporaryDetach);
   3914                 assertFalse(mExitedDispatchStartTemporaryDetach);
   3915                 assertFalse(mEnteredDispatchFinishTemporaryDetach);
   3916                 assertFalse(mExitedDispatchFinishTemporaryDetach);
   3917                 assertFalse(mCalledOnStartTemporaryDetach);
   3918                 assertFalse(mCalledOnFinishTemporaryDetach);
   3919                 mEnteredDispatchStartTemporaryDetach = true;
   3920 
   3921                 assertFalse(isTemporarilyDetached());
   3922 
   3923                 super.dispatchStartTemporaryDetach();
   3924 
   3925                 assertTrue(isTemporarilyDetached());
   3926 
   3927                 assertTrue(mEnteredDispatchStartTemporaryDetach);
   3928                 assertFalse(mExitedDispatchStartTemporaryDetach);
   3929                 assertFalse(mEnteredDispatchFinishTemporaryDetach);
   3930                 assertFalse(mExitedDispatchFinishTemporaryDetach);
   3931                 assertTrue(mCalledOnStartTemporaryDetach);
   3932                 assertFalse(mCalledOnFinishTemporaryDetach);
   3933                 mExitedDispatchStartTemporaryDetach = true;
   3934                 exitedDispatchStartTemporaryDetach.set(true);
   3935             }
   3936 
   3937             @Override
   3938             public void dispatchFinishTemporaryDetach() {
   3939                 assertTrue(mEnteredDispatchStartTemporaryDetach);
   3940                 assertTrue(mExitedDispatchStartTemporaryDetach);
   3941                 assertFalse(mEnteredDispatchFinishTemporaryDetach);
   3942                 assertFalse(mExitedDispatchFinishTemporaryDetach);
   3943                 assertTrue(mCalledOnStartTemporaryDetach);
   3944                 assertFalse(mCalledOnFinishTemporaryDetach);
   3945                 mEnteredDispatchFinishTemporaryDetach = true;
   3946 
   3947                 assertTrue(isTemporarilyDetached());
   3948 
   3949                 super.dispatchFinishTemporaryDetach();
   3950 
   3951                 assertFalse(isTemporarilyDetached());
   3952 
   3953                 assertTrue(mEnteredDispatchStartTemporaryDetach);
   3954                 assertTrue(mExitedDispatchStartTemporaryDetach);
   3955                 assertTrue(mEnteredDispatchFinishTemporaryDetach);
   3956                 assertFalse(mExitedDispatchFinishTemporaryDetach);
   3957                 assertTrue(mCalledOnStartTemporaryDetach);
   3958                 assertTrue(mCalledOnFinishTemporaryDetach);
   3959                 mExitedDispatchFinishTemporaryDetach = true;
   3960                 exitedDispatchFinishTemporaryDetach.set(true);
   3961             }
   3962 
   3963             @Override
   3964             public void onStartTemporaryDetach() {
   3965                 assertTrue(mEnteredDispatchStartTemporaryDetach);
   3966                 assertFalse(mExitedDispatchStartTemporaryDetach);
   3967                 assertFalse(mEnteredDispatchFinishTemporaryDetach);
   3968                 assertFalse(mExitedDispatchFinishTemporaryDetach);
   3969                 assertFalse(mCalledOnStartTemporaryDetach);
   3970                 assertFalse(mCalledOnFinishTemporaryDetach);
   3971 
   3972                 assertTrue(isTemporarilyDetached());
   3973 
   3974                 mCalledOnStartTemporaryDetach = true;
   3975             }
   3976 
   3977             @Override
   3978             public void onFinishTemporaryDetach() {
   3979                 assertTrue(mEnteredDispatchStartTemporaryDetach);
   3980                 assertTrue(mExitedDispatchStartTemporaryDetach);
   3981                 assertTrue(mEnteredDispatchFinishTemporaryDetach);
   3982                 assertFalse(mExitedDispatchFinishTemporaryDetach);
   3983                 assertTrue(mCalledOnStartTemporaryDetach);
   3984                 assertFalse(mCalledOnFinishTemporaryDetach);
   3985 
   3986                 assertFalse(isTemporarilyDetached());
   3987 
   3988                 mCalledOnFinishTemporaryDetach = true;
   3989             }
   3990         };
   3991 
   3992         assertFalse(view.isTemporarilyDetached());
   3993 
   3994         mActivityRule.runOnUiThread(view::dispatchStartTemporaryDetach);
   3995         mInstrumentation.waitForIdleSync();
   3996 
   3997         assertTrue(view.isTemporarilyDetached());
   3998         assertTrue(exitedDispatchStartTemporaryDetach.get());
   3999         assertFalse(exitedDispatchFinishTemporaryDetach.get());
   4000 
   4001         mActivityRule.runOnUiThread(view::dispatchFinishTemporaryDetach);
   4002         mInstrumentation.waitForIdleSync();
   4003 
   4004         assertFalse(view.isTemporarilyDetached());
   4005         assertTrue(exitedDispatchStartTemporaryDetach.get());
   4006         assertTrue(exitedDispatchFinishTemporaryDetach.get());
   4007     }
   4008 
   4009     @Test
   4010     public void testKeyPreIme() throws Throwable {
   4011         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   4012 
   4013         mActivityRule.runOnUiThread(() -> {
   4014             view.setFocusable(true);
   4015             view.requestFocus();
   4016         });
   4017         mInstrumentation.waitForIdleSync();
   4018 
   4019         mInstrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
   4020         assertTrue(view.hasCalledDispatchKeyEventPreIme());
   4021         assertTrue(view.hasCalledOnKeyPreIme());
   4022     }
   4023 
   4024     @Test
   4025     public void testHapticFeedback() {
   4026         Vibrator vib = (Vibrator) mActivity.getSystemService(Context.VIBRATOR_SERVICE);
   4027         boolean hasVibrator = vib.hasVibrator();
   4028 
   4029         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   4030         final int LONG_PRESS = HapticFeedbackConstants.LONG_PRESS;
   4031         final int FLAG_IGNORE_VIEW_SETTING = HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING;
   4032         final int FLAG_IGNORE_GLOBAL_SETTING = HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING;
   4033         final int ALWAYS = FLAG_IGNORE_VIEW_SETTING | FLAG_IGNORE_GLOBAL_SETTING;
   4034 
   4035         view.setHapticFeedbackEnabled(false);
   4036         assertFalse(view.isHapticFeedbackEnabled());
   4037         assertFalse(view.performHapticFeedback(LONG_PRESS));
   4038         assertFalse(view.performHapticFeedback(LONG_PRESS, FLAG_IGNORE_GLOBAL_SETTING));
   4039         assertEquals(hasVibrator, view.performHapticFeedback(LONG_PRESS, ALWAYS));
   4040 
   4041         view.setHapticFeedbackEnabled(true);
   4042         assertTrue(view.isHapticFeedbackEnabled());
   4043         assertEquals(hasVibrator, view.performHapticFeedback(LONG_PRESS,
   4044                 FLAG_IGNORE_GLOBAL_SETTING));
   4045     }
   4046 
   4047     @Test
   4048     public void testInputConnection() throws Throwable {
   4049         final InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(
   4050                 Context.INPUT_METHOD_SERVICE);
   4051         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
   4052         final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
   4053         final MockEditText editText = new MockEditText(mActivity);
   4054 
   4055         mActivityRule.runOnUiThread(() -> {
   4056             // Give a fixed size since, on most devices, the edittext is off-screen
   4057             // and therefore doesn't get laid-out properly.
   4058             viewGroup.addView(editText, 100, 30);
   4059             editText.requestFocus();
   4060         });
   4061         mInstrumentation.waitForIdleSync();
   4062         assertTrue(editText.isFocused());
   4063 
   4064         mActivityRule.runOnUiThread(() -> imm.showSoftInput(editText, 0));
   4065         mInstrumentation.waitForIdleSync();
   4066 
   4067         PollingCheck.waitFor(TIMEOUT_DELTA, editText::hasCalledOnCreateInputConnection);
   4068 
   4069         assertTrue(editText.hasCalledOnCheckIsTextEditor());
   4070 
   4071         mActivityRule.runOnUiThread(() -> {
   4072             assertTrue(imm.isActive(editText));
   4073             assertFalse(editText.hasCalledCheckInputConnectionProxy());
   4074             imm.isActive(view);
   4075             assertTrue(editText.hasCalledCheckInputConnectionProxy());
   4076         });
   4077     }
   4078 
   4079     @Test
   4080     public void testFilterTouchesWhenObscured() throws Throwable {
   4081         View.OnTouchListener touchListener = mock(View.OnTouchListener.class);
   4082         doReturn(true).when(touchListener).onTouch(any(), any());
   4083         View view = new View(mActivity);
   4084         view.setOnTouchListener(touchListener);
   4085 
   4086         MotionEvent.PointerProperties[] props = new MotionEvent.PointerProperties[] {
   4087                 new MotionEvent.PointerProperties()
   4088         };
   4089         MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[] {
   4090                 new MotionEvent.PointerCoords()
   4091         };
   4092         MotionEvent obscuredTouch = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN,
   4093                 1, props, coords, 0, 0, 0, 0, -1, 0, InputDevice.SOURCE_TOUCHSCREEN,
   4094                 MotionEvent.FLAG_WINDOW_IS_OBSCURED);
   4095         MotionEvent unobscuredTouch = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN,
   4096                 1, props, coords, 0, 0, 0, 0, -1, 0, InputDevice.SOURCE_TOUCHSCREEN,
   4097                 0);
   4098 
   4099         // Initially filter touches is false so all touches are dispatched.
   4100         assertFalse(view.getFilterTouchesWhenObscured());
   4101 
   4102         view.dispatchTouchEvent(unobscuredTouch);
   4103         verify(touchListener, times(1)).onTouch(view, unobscuredTouch);
   4104         reset(touchListener);
   4105         view.dispatchTouchEvent(obscuredTouch);
   4106         verify(touchListener, times(1)).onTouch(view, obscuredTouch);
   4107         reset(touchListener);
   4108 
   4109         // Set filter touches to true so only unobscured touches are dispatched.
   4110         view.setFilterTouchesWhenObscured(true);
   4111         assertTrue(view.getFilterTouchesWhenObscured());
   4112 
   4113         view.dispatchTouchEvent(unobscuredTouch);
   4114         verify(touchListener, times(1)).onTouch(view, unobscuredTouch);
   4115         reset(touchListener);
   4116         view.dispatchTouchEvent(obscuredTouch);
   4117         verifyZeroInteractions(touchListener);
   4118         reset(touchListener);
   4119 
   4120         // Set filter touches to false so all touches are dispatched.
   4121         view.setFilterTouchesWhenObscured(false);
   4122         assertFalse(view.getFilterTouchesWhenObscured());
   4123 
   4124         view.dispatchTouchEvent(unobscuredTouch);
   4125         verify(touchListener, times(1)).onTouch(view, unobscuredTouch);
   4126         reset(touchListener);
   4127         view.dispatchTouchEvent(obscuredTouch);
   4128         verify(touchListener, times(1)).onTouch(view, obscuredTouch);
   4129         reset(touchListener);
   4130     }
   4131 
   4132     @Test
   4133     public void testBackgroundTint() {
   4134         View inflatedView = mActivity.findViewById(R.id.background_tint);
   4135 
   4136         assertEquals("Background tint inflated correctly",
   4137                 Color.WHITE, inflatedView.getBackgroundTintList().getDefaultColor());
   4138         assertEquals("Background tint mode inflated correctly",
   4139                 PorterDuff.Mode.SRC_OVER, inflatedView.getBackgroundTintMode());
   4140 
   4141         MockDrawable bg = new MockDrawable();
   4142         View view = new View(mActivity);
   4143 
   4144         view.setBackground(bg);
   4145         assertFalse("No background tint applied by default", bg.hasCalledSetTint());
   4146 
   4147         view.setBackgroundTintList(ColorStateList.valueOf(Color.WHITE));
   4148         assertTrue("Background tint applied when setBackgroundTints() called after setBackground()",
   4149                 bg.hasCalledSetTint());
   4150 
   4151         bg.reset();
   4152         view.setBackground(null);
   4153         view.setBackground(bg);
   4154         assertTrue("Background tint applied when setBackgroundTints() called before setBackground()",
   4155                 bg.hasCalledSetTint());
   4156     }
   4157 
   4158     @Test
   4159     public void testStartActionModeWithParent() {
   4160         View view = new View(mActivity);
   4161         MockViewGroup parent = new MockViewGroup(mActivity);
   4162         parent.addView(view);
   4163 
   4164         ActionMode mode = view.startActionMode(null);
   4165 
   4166         assertNotNull(mode);
   4167         assertEquals(NO_OP_ACTION_MODE, mode);
   4168         assertTrue(parent.isStartActionModeForChildCalled);
   4169         assertEquals(ActionMode.TYPE_PRIMARY, parent.startActionModeForChildType);
   4170     }
   4171 
   4172     @Test
   4173     public void testStartActionModeWithoutParent() {
   4174         View view = new View(mActivity);
   4175 
   4176         ActionMode mode = view.startActionMode(null);
   4177 
   4178         assertNull(mode);
   4179     }
   4180 
   4181     @Test
   4182     public void testStartActionModeTypedWithParent() {
   4183         View view = new View(mActivity);
   4184         MockViewGroup parent = new MockViewGroup(mActivity);
   4185         parent.addView(view);
   4186 
   4187         ActionMode mode = view.startActionMode(null, ActionMode.TYPE_FLOATING);
   4188 
   4189         assertNotNull(mode);
   4190         assertEquals(NO_OP_ACTION_MODE, mode);
   4191         assertTrue(parent.isStartActionModeForChildCalled);
   4192         assertEquals(ActionMode.TYPE_FLOATING, parent.startActionModeForChildType);
   4193     }
   4194 
   4195     @Test
   4196     public void testStartActionModeTypedWithoutParent() {
   4197         View view = new View(mActivity);
   4198 
   4199         ActionMode mode = view.startActionMode(null, ActionMode.TYPE_FLOATING);
   4200 
   4201         assertNull(mode);
   4202     }
   4203 
   4204     @Test
   4205     public void testVisibilityAggregated() throws Throwable {
   4206         final View grandparent = mActivity.findViewById(R.id.viewlayout_root);
   4207         final View parent = mActivity.findViewById(R.id.aggregate_visibility_parent);
   4208         final MockView mv = (MockView) mActivity.findViewById(R.id.mock_view_aggregate_visibility);
   4209 
   4210         assertEquals(parent, mv.getParent());
   4211         assertEquals(grandparent, parent.getParent());
   4212 
   4213         assertTrue(mv.hasCalledOnVisibilityAggregated());
   4214         assertTrue(mv.getLastAggregatedVisibility());
   4215 
   4216         final Runnable reset = () -> {
   4217             grandparent.setVisibility(View.VISIBLE);
   4218             parent.setVisibility(View.VISIBLE);
   4219             mv.setVisibility(View.VISIBLE);
   4220             mv.reset();
   4221         };
   4222 
   4223         mActivityRule.runOnUiThread(reset);
   4224 
   4225         setVisibilityOnUiThread(parent, View.GONE);
   4226 
   4227         assertTrue(mv.hasCalledOnVisibilityAggregated());
   4228         assertFalse(mv.getLastAggregatedVisibility());
   4229 
   4230         mActivityRule.runOnUiThread(reset);
   4231 
   4232         setVisibilityOnUiThread(grandparent, View.GONE);
   4233 
   4234         assertTrue(mv.hasCalledOnVisibilityAggregated());
   4235         assertFalse(mv.getLastAggregatedVisibility());
   4236 
   4237         mActivityRule.runOnUiThread(reset);
   4238         mActivityRule.runOnUiThread(() -> {
   4239             grandparent.setVisibility(View.GONE);
   4240             parent.setVisibility(View.GONE);
   4241             mv.setVisibility(View.VISIBLE);
   4242 
   4243             grandparent.setVisibility(View.VISIBLE);
   4244         });
   4245 
   4246         assertTrue(mv.hasCalledOnVisibilityAggregated());
   4247         assertFalse(mv.getLastAggregatedVisibility());
   4248 
   4249         mActivityRule.runOnUiThread(reset);
   4250         mActivityRule.runOnUiThread(() -> {
   4251             grandparent.setVisibility(View.GONE);
   4252             parent.setVisibility(View.INVISIBLE);
   4253 
   4254             grandparent.setVisibility(View.VISIBLE);
   4255         });
   4256 
   4257         assertTrue(mv.hasCalledOnVisibilityAggregated());
   4258         assertFalse(mv.getLastAggregatedVisibility());
   4259 
   4260         mActivityRule.runOnUiThread(() -> parent.setVisibility(View.VISIBLE));
   4261 
   4262         assertTrue(mv.getLastAggregatedVisibility());
   4263     }
   4264 
   4265     @Test
   4266     public void testOverlappingRendering() {
   4267         View overlappingUnsetView = mActivity.findViewById(R.id.overlapping_rendering_unset);
   4268         View overlappingFalseView = mActivity.findViewById(R.id.overlapping_rendering_false);
   4269         View overlappingTrueView = mActivity.findViewById(R.id.overlapping_rendering_true);
   4270 
   4271         assertTrue(overlappingUnsetView.hasOverlappingRendering());
   4272         assertTrue(overlappingUnsetView.getHasOverlappingRendering());
   4273         overlappingUnsetView.forceHasOverlappingRendering(false);
   4274         assertTrue(overlappingUnsetView.hasOverlappingRendering());
   4275         assertFalse(overlappingUnsetView.getHasOverlappingRendering());
   4276         overlappingUnsetView.forceHasOverlappingRendering(true);
   4277         assertTrue(overlappingUnsetView.hasOverlappingRendering());
   4278         assertTrue(overlappingUnsetView.getHasOverlappingRendering());
   4279 
   4280         assertTrue(overlappingTrueView.hasOverlappingRendering());
   4281         assertTrue(overlappingTrueView.getHasOverlappingRendering());
   4282 
   4283         assertTrue(overlappingFalseView.hasOverlappingRendering());
   4284         assertFalse(overlappingFalseView.getHasOverlappingRendering());
   4285 
   4286         View overridingView = new MockOverlappingRenderingSubclass(mActivity, false);
   4287         assertFalse(overridingView.hasOverlappingRendering());
   4288 
   4289         overridingView = new MockOverlappingRenderingSubclass(mActivity, true);
   4290         assertTrue(overridingView.hasOverlappingRendering());
   4291         overridingView.forceHasOverlappingRendering(false);
   4292         assertFalse(overridingView.getHasOverlappingRendering());
   4293         assertTrue(overridingView.hasOverlappingRendering());
   4294         overridingView.forceHasOverlappingRendering(true);
   4295         assertTrue(overridingView.getHasOverlappingRendering());
   4296         assertTrue(overridingView.hasOverlappingRendering());
   4297     }
   4298 
   4299     private boolean startDragAndDrop(View view, View.DragShadowBuilder shadowBuilder) {
   4300         final Point size = new Point();
   4301         mActivity.getDisplay().getSize(size);
   4302         final MotionEvent event = MotionEvent.obtain(
   4303                 SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
   4304                 MotionEvent.ACTION_DOWN, size.x / 2, size.y / 2, 1);
   4305         event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
   4306         mInstrumentation.getUiAutomation().injectInputEvent(event, true);
   4307 
   4308         return view.startDragAndDrop(ClipData.newPlainText("", ""), shadowBuilder, view, 0);
   4309     }
   4310 
   4311     private static View.DragShadowBuilder createDragShadowBuidler() {
   4312         View.DragShadowBuilder shadowBuilder = mock(View.DragShadowBuilder.class);
   4313         doAnswer(a -> {
   4314             final Point outPoint = (Point) a.getArguments()[0];
   4315             outPoint.x = 1;
   4316             outPoint.y = 1;
   4317             return null;
   4318         }).when(shadowBuilder).onProvideShadowMetrics(any(), any());
   4319         return shadowBuilder;
   4320     }
   4321 
   4322     @Test
   4323     public void testUpdateDragShadow() {
   4324         View view = mActivity.findViewById(R.id.fit_windows);
   4325         assertTrue(view.isAttachedToWindow());
   4326 
   4327         final View.DragShadowBuilder shadowBuilder = createDragShadowBuidler();
   4328         try {
   4329             assertTrue("Could not start drag and drop", startDragAndDrop(view, shadowBuilder));
   4330             reset(shadowBuilder);
   4331             view.updateDragShadow(shadowBuilder);
   4332             // TODO: Verify with the canvas from the drag surface instead.
   4333             verify(shadowBuilder).onDrawShadow(any(Canvas.class));
   4334         } finally {
   4335             // Ensure to cancel drag and drop operation so that it does not affect other tests.
   4336             view.cancelDragAndDrop();
   4337         }
   4338     }
   4339 
   4340     @Test
   4341     public void testUpdateDragShadow_detachedView() {
   4342         View view = new View(mActivity);
   4343         assertFalse(view.isAttachedToWindow());
   4344 
   4345         View.DragShadowBuilder shadowBuilder = createDragShadowBuidler();
   4346         try {
   4347             assertFalse("Drag and drop for detached view must fail",
   4348                     startDragAndDrop(view, shadowBuilder));
   4349             reset(shadowBuilder);
   4350 
   4351             view.updateDragShadow(shadowBuilder);
   4352             verify(shadowBuilder, never()).onDrawShadow(any(Canvas.class));
   4353         } finally {
   4354             // Ensure to cancel drag and drop operation so that it does not affect other tests.
   4355             view.cancelDragAndDrop();
   4356         }
   4357     }
   4358 
   4359     @Test
   4360     public void testUpdateDragShadow_noActiveDrag() {
   4361         View view = mActivity.findViewById(R.id.fit_windows);
   4362         assertTrue(view.isAttachedToWindow());
   4363 
   4364         View.DragShadowBuilder shadowBuilder = createDragShadowBuidler();
   4365         view.updateDragShadow(shadowBuilder);
   4366         verify(shadowBuilder, never()).onDrawShadow(any(Canvas.class));
   4367     }
   4368 
   4369     private void setVisibilityOnUiThread(final View view, final int visibility) throws Throwable {
   4370         mActivityRule.runOnUiThread(() -> view.setVisibility(visibility));
   4371     }
   4372 
   4373     private static class MockOverlappingRenderingSubclass extends View {
   4374         boolean mOverlap;
   4375 
   4376         public MockOverlappingRenderingSubclass(Context context, boolean overlap) {
   4377             super(context);
   4378             mOverlap = overlap;
   4379         }
   4380 
   4381         @Override
   4382         public boolean hasOverlappingRendering() {
   4383             return mOverlap;
   4384         }
   4385     }
   4386 
   4387     private static class MockViewGroup extends ViewGroup {
   4388         boolean isStartActionModeForChildCalled = false;
   4389         int startActionModeForChildType = ActionMode.TYPE_PRIMARY;
   4390 
   4391         public MockViewGroup(Context context) {
   4392             super(context);
   4393         }
   4394 
   4395         @Override
   4396         public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
   4397             isStartActionModeForChildCalled = true;
   4398             startActionModeForChildType = ActionMode.TYPE_PRIMARY;
   4399             return NO_OP_ACTION_MODE;
   4400         }
   4401 
   4402         @Override
   4403         public ActionMode startActionModeForChild(
   4404                 View originalView, ActionMode.Callback callback, int type) {
   4405             isStartActionModeForChildCalled = true;
   4406             startActionModeForChildType = type;
   4407             return NO_OP_ACTION_MODE;
   4408         }
   4409 
   4410         @Override
   4411         protected void onLayout(boolean changed, int l, int t, int r, int b) {
   4412             // no-op
   4413         }
   4414     }
   4415 
   4416     private static final ActionMode NO_OP_ACTION_MODE =
   4417             new ActionMode() {
   4418                 @Override
   4419                 public void setTitle(CharSequence title) {}
   4420 
   4421                 @Override
   4422                 public void setTitle(int resId) {}
   4423 
   4424                 @Override
   4425                 public void setSubtitle(CharSequence subtitle) {}
   4426 
   4427                 @Override
   4428                 public void setSubtitle(int resId) {}
   4429 
   4430                 @Override
   4431                 public void setCustomView(View view) {}
   4432 
   4433                 @Override
   4434                 public void invalidate() {}
   4435 
   4436                 @Override
   4437                 public void finish() {}
   4438 
   4439                 @Override
   4440                 public Menu getMenu() {
   4441                     return null;
   4442                 }
   4443 
   4444                 @Override
   4445                 public CharSequence getTitle() {
   4446                     return null;
   4447                 }
   4448 
   4449                 @Override
   4450                 public CharSequence getSubtitle() {
   4451                     return null;
   4452                 }
   4453 
   4454                 @Override
   4455                 public View getCustomView() {
   4456                     return null;
   4457                 }
   4458 
   4459                 @Override
   4460                 public MenuInflater getMenuInflater() {
   4461                     return null;
   4462                 }
   4463             };
   4464 
   4465     @Test
   4466     public void testTranslationSetter() {
   4467         View view = new View(mActivity);
   4468         float offset = 10.0f;
   4469         view.setTranslationX(offset);
   4470         view.setTranslationY(offset);
   4471         view.setTranslationZ(offset);
   4472         view.setElevation(offset);
   4473 
   4474         assertEquals("Incorrect translationX", offset, view.getTranslationX(), 0.0f);
   4475         assertEquals("Incorrect translationY", offset, view.getTranslationY(), 0.0f);
   4476         assertEquals("Incorrect translationZ", offset, view.getTranslationZ(), 0.0f);
   4477         assertEquals("Incorrect elevation", offset, view.getElevation(), 0.0f);
   4478     }
   4479 
   4480     @Test
   4481     public void testXYZ() {
   4482         View view = new View(mActivity);
   4483         float offset = 10.0f;
   4484         float start = 15.0f;
   4485         view.setTranslationX(offset);
   4486         view.setLeft((int) start);
   4487         view.setTranslationY(offset);
   4488         view.setTop((int) start);
   4489         view.setTranslationZ(offset);
   4490         view.setElevation(start);
   4491 
   4492         assertEquals("Incorrect X value", offset + start, view.getX(), 0.0f);
   4493         assertEquals("Incorrect Y value", offset + start, view.getY(), 0.0f);
   4494         assertEquals("Incorrect Z value", offset + start, view.getZ(), 0.0f);
   4495     }
   4496 
   4497     @Test
   4498     public void testOnHoverEvent() {
   4499         MotionEvent event;
   4500 
   4501         View view = new View(mActivity);
   4502         long downTime = SystemClock.uptimeMillis();
   4503 
   4504         // Preconditions.
   4505         assertFalse(view.isHovered());
   4506         assertFalse(view.isClickable());
   4507         assertTrue(view.isEnabled());
   4508 
   4509         // Simulate an ENTER/EXIT pair on a non-clickable view.
   4510         event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0);
   4511         view.onHoverEvent(event);
   4512         assertFalse(view.isHovered());
   4513         event.recycle();
   4514 
   4515         event = MotionEvent.obtain(downTime, downTime + 10, MotionEvent.ACTION_HOVER_EXIT, 0, 0, 0);
   4516         view.onHoverEvent(event);
   4517         assertFalse(view.isHovered());
   4518         event.recycle();
   4519 
   4520         // Simulate an ENTER/EXIT pair on a clickable view.
   4521         view.setClickable(true);
   4522 
   4523         event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0);
   4524         view.onHoverEvent(event);
   4525         assertTrue(view.isHovered());
   4526         event.recycle();
   4527 
   4528         event = MotionEvent.obtain(downTime, downTime + 10, MotionEvent.ACTION_HOVER_EXIT, 0, 0, 0);
   4529         view.onHoverEvent(event);
   4530         assertFalse(view.isHovered());
   4531         event.recycle();
   4532 
   4533         // Simulate an ENTER, then disable the view and simulate EXIT.
   4534         event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0);
   4535         view.onHoverEvent(event);
   4536         assertTrue(view.isHovered());
   4537         event.recycle();
   4538 
   4539         view.setEnabled(false);
   4540 
   4541         event = MotionEvent.obtain(downTime, downTime + 10, MotionEvent.ACTION_HOVER_EXIT, 0, 0, 0);
   4542         view.onHoverEvent(event);
   4543         assertFalse(view.isHovered());
   4544         event.recycle();
   4545     }
   4546 
   4547     @Test(expected = IllegalArgumentException.class)
   4548     public void testScaleXNaN() {
   4549         View view = new View(mContext);
   4550         view.setScaleX(Float.NaN);
   4551     }
   4552 
   4553     @Test(expected = IllegalArgumentException.class)
   4554     public void testScaleXPositiveInfinity() {
   4555         View view = new View(mContext);
   4556         view.setScaleX(Float.POSITIVE_INFINITY);
   4557     }
   4558 
   4559     @Test(expected = IllegalArgumentException.class)
   4560     public void testScaleXNegativeInfinity() {
   4561         View view = new View(mContext);
   4562         view.setScaleX(Float.NEGATIVE_INFINITY);
   4563     }
   4564 
   4565     @Test(expected = IllegalArgumentException.class)
   4566     public void testScaleYNaN() {
   4567         View view = new View(mContext);
   4568         view.setScaleY(Float.NaN);
   4569     }
   4570 
   4571     @Test(expected = IllegalArgumentException.class)
   4572     public void testScaleYPositiveInfinity() {
   4573         View view = new View(mContext);
   4574         view.setScaleY(Float.POSITIVE_INFINITY);
   4575     }
   4576 
   4577     @Test(expected = IllegalArgumentException.class)
   4578     public void testScaleYNegativeInfinity() {
   4579         View view = new View(mContext);
   4580         view.setScaleY(Float.NEGATIVE_INFINITY);
   4581     }
   4582 
   4583     @Test
   4584     public void testSetGetOutlineShadowColor() {
   4585         ViewGroup group = (ViewGroup) LayoutInflater.from(mContext).inflate(
   4586                 R.layout.view_outlineshadowcolor, null);
   4587         View defaultShadow = group.findViewById(R.id.default_shadow);
   4588         assertEquals(Color.BLACK, defaultShadow.getOutlineSpotShadowColor());
   4589         assertEquals(Color.BLACK, defaultShadow.getOutlineAmbientShadowColor());
   4590         defaultShadow.setOutlineSpotShadowColor(Color.YELLOW);
   4591         defaultShadow.setOutlineAmbientShadowColor(Color.GREEN);
   4592         assertEquals(Color.YELLOW, defaultShadow.getOutlineSpotShadowColor());
   4593         assertEquals(Color.GREEN, defaultShadow.getOutlineAmbientShadowColor());
   4594 
   4595         View redAmbientShadow = group.findViewById(R.id.red_shadow);
   4596         assertEquals(Color.RED, redAmbientShadow.getOutlineAmbientShadowColor());
   4597         assertEquals(Color.BLACK, redAmbientShadow.getOutlineSpotShadowColor());
   4598 
   4599         View blueSpotShadow = group.findViewById(R.id.blue_shadow);
   4600         assertEquals(Color.BLUE, blueSpotShadow.getOutlineSpotShadowColor());
   4601         assertEquals(Color.BLACK, blueSpotShadow.getOutlineAmbientShadowColor());
   4602 
   4603         View greenShadow = group.findViewById(R.id.green_shadow);
   4604         assertEquals(Color.GREEN, greenShadow.getOutlineSpotShadowColor());
   4605         assertEquals(Color.GREEN, greenShadow.getOutlineAmbientShadowColor());
   4606     }
   4607 
   4608     @Test
   4609     public void testPivot() {
   4610         View view = new View(mContext);
   4611         int widthSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
   4612         int heightSpec = View.MeasureSpec.makeMeasureSpec(200, View.MeasureSpec.EXACTLY);
   4613         view.measure(widthSpec, heightSpec);
   4614         assertEquals(100, view.getMeasuredWidth());
   4615         assertEquals(200, view.getMeasuredHeight());
   4616         view.layout(0, 0, 100, 200);
   4617         assertEquals(100, view.getWidth());
   4618         assertEquals(200, view.getHeight());
   4619 
   4620         // Assert default pivot behavior
   4621         assertEquals(50, view.getPivotX(), 0.0f);
   4622         assertEquals(100, view.getPivotY(), 0.0f);
   4623         assertFalse(view.isPivotSet());
   4624 
   4625         // Assert it changes as expected
   4626         view.setPivotX(15);
   4627         assertEquals(15, view.getPivotX(), 0.0f);
   4628         assertEquals(100, view.getPivotY(), 0.0f);
   4629         assertTrue(view.isPivotSet());
   4630         view.setPivotY(0);
   4631         assertEquals(0, view.getPivotY(), 0.0f);
   4632         assertTrue(view.isPivotSet());
   4633 
   4634         // Asset resetting back to default
   4635         view.resetPivot();
   4636         assertEquals(50, view.getPivotX(), 0.0f);
   4637         assertEquals(100, view.getPivotY(), 0.0f);
   4638         assertFalse(view.isPivotSet());
   4639     }
   4640 
   4641     private static class MockDrawable extends Drawable {
   4642         private boolean mCalledSetTint = false;
   4643 
   4644         @Override
   4645         public void draw(Canvas canvas) {}
   4646 
   4647         @Override
   4648         public void setAlpha(int alpha) {}
   4649 
   4650         @Override
   4651         public void setColorFilter(ColorFilter cf) {}
   4652 
   4653         @Override
   4654         public int getOpacity() {
   4655             return 0;
   4656         }
   4657 
   4658         @Override
   4659         public void setTintList(ColorStateList tint) {
   4660             super.setTintList(tint);
   4661             mCalledSetTint = true;
   4662         }
   4663 
   4664         public boolean hasCalledSetTint() {
   4665             return mCalledSetTint;
   4666         }
   4667 
   4668         public void reset() {
   4669             mCalledSetTint = false;
   4670         }
   4671     }
   4672 
   4673     private static class MockEditText extends EditText {
   4674         private boolean mCalledCheckInputConnectionProxy = false;
   4675         private boolean mCalledOnCreateInputConnection = false;
   4676         private boolean mCalledOnCheckIsTextEditor = false;
   4677 
   4678         public MockEditText(Context context) {
   4679             super(context);
   4680         }
   4681 
   4682         @Override
   4683         public boolean checkInputConnectionProxy(View view) {
   4684             mCalledCheckInputConnectionProxy = true;
   4685             return super.checkInputConnectionProxy(view);
   4686         }
   4687 
   4688         public boolean hasCalledCheckInputConnectionProxy() {
   4689             return mCalledCheckInputConnectionProxy;
   4690         }
   4691 
   4692         @Override
   4693         public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
   4694             mCalledOnCreateInputConnection = true;
   4695             return super.onCreateInputConnection(outAttrs);
   4696         }
   4697 
   4698         public boolean hasCalledOnCreateInputConnection() {
   4699             return mCalledOnCreateInputConnection;
   4700         }
   4701 
   4702         @Override
   4703         public boolean onCheckIsTextEditor() {
   4704             mCalledOnCheckIsTextEditor = true;
   4705             return super.onCheckIsTextEditor();
   4706         }
   4707 
   4708         public boolean hasCalledOnCheckIsTextEditor() {
   4709             return mCalledOnCheckIsTextEditor;
   4710         }
   4711 
   4712         public void reset() {
   4713             mCalledCheckInputConnectionProxy = false;
   4714             mCalledOnCreateInputConnection = false;
   4715             mCalledOnCheckIsTextEditor = false;
   4716         }
   4717     }
   4718 
   4719     private final static class MockViewParent extends ViewGroup {
   4720         private boolean mHasRequestLayout = false;
   4721         private boolean mHasCreateContextMenu = false;
   4722         private boolean mHasShowContextMenuForChild = false;
   4723         private boolean mHasShowContextMenuForChildXY = false;
   4724         private boolean mHasChildDrawableStateChanged = false;
   4725         private boolean mHasBroughtChildToFront = false;
   4726 
   4727         private final static int[] DEFAULT_PARENT_STATE_SET = new int[] { 789 };
   4728 
   4729         @Override
   4730         public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
   4731                 boolean immediate) {
   4732             return false;
   4733         }
   4734 
   4735         public MockViewParent(Context context) {
   4736             super(context);
   4737         }
   4738 
   4739         @Override
   4740         public void bringChildToFront(View child) {
   4741             mHasBroughtChildToFront = true;
   4742         }
   4743 
   4744         public boolean hasBroughtChildToFront() {
   4745             return mHasBroughtChildToFront;
   4746         }
   4747 
   4748         @Override
   4749         public void childDrawableStateChanged(View child) {
   4750             mHasChildDrawableStateChanged = true;
   4751         }
   4752 
   4753         public boolean hasChildDrawableStateChanged() {
   4754             return mHasChildDrawableStateChanged;
   4755         }
   4756 
   4757         @Override
   4758         public void dispatchSetPressed(boolean pressed) {
   4759             super.dispatchSetPressed(pressed);
   4760         }
   4761 
   4762         @Override
   4763         public void dispatchSetSelected(boolean selected) {
   4764             super.dispatchSetSelected(selected);
   4765         }
   4766 
   4767         @Override
   4768         public void clearChildFocus(View child) {
   4769 
   4770         }
   4771 
   4772         @Override
   4773         public void createContextMenu(ContextMenu menu) {
   4774             mHasCreateContextMenu = true;
   4775         }
   4776 
   4777         public boolean hasCreateContextMenu() {
   4778             return mHasCreateContextMenu;
   4779         }
   4780 
   4781         @Override
   4782         public View focusSearch(View v, int direction) {
   4783             return v;
   4784         }
   4785 
   4786         @Override
   4787         public void focusableViewAvailable(View v) {
   4788 
   4789         }
   4790 
   4791         @Override
   4792         public boolean getChildVisibleRect(View child, Rect r, Point offset) {
   4793             return false;
   4794         }
   4795 
   4796         @Override
   4797         protected void onLayout(boolean changed, int l, int t, int r, int b) {
   4798 
   4799         }
   4800 
   4801         @Override
   4802         public ViewParent invalidateChildInParent(int[] location, Rect r) {
   4803             return null;
   4804         }
   4805 
   4806         @Override
   4807         public boolean isLayoutRequested() {
   4808             return false;
   4809         }
   4810 
   4811         @Override
   4812         public void recomputeViewAttributes(View child) {
   4813 
   4814         }
   4815 
   4816         @Override
   4817         public void requestChildFocus(View child, View focused) {
   4818 
   4819         }
   4820 
   4821         @Override
   4822         public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
   4823 
   4824         }
   4825 
   4826         @Override
   4827         public void requestLayout() {
   4828             mHasRequestLayout = true;
   4829         }
   4830 
   4831         public boolean hasRequestLayout() {
   4832             return mHasRequestLayout;
   4833         }
   4834 
   4835         @Override
   4836         public void requestTransparentRegion(View child) {
   4837 
   4838         }
   4839 
   4840         @Override
   4841         public boolean showContextMenuForChild(View originalView) {
   4842             mHasShowContextMenuForChild = true;
   4843             return false;
   4844         }
   4845 
   4846         @Override
   4847         public boolean showContextMenuForChild(View originalView, float x, float y) {
   4848             mHasShowContextMenuForChildXY = true;
   4849             return false;
   4850         }
   4851 
   4852         @Override
   4853         public ActionMode startActionModeForChild(View originalView,
   4854                 ActionMode.Callback callback) {
   4855             return null;
   4856         }
   4857 
   4858         @Override
   4859         public ActionMode startActionModeForChild(View originalView,
   4860                 ActionMode.Callback callback, int type) {
   4861             return null;
   4862         }
   4863 
   4864         public boolean hasShowContextMenuForChild() {
   4865             return mHasShowContextMenuForChild;
   4866         }
   4867 
   4868         public boolean hasShowContextMenuForChildXY() {
   4869             return mHasShowContextMenuForChildXY;
   4870         }
   4871 
   4872         @Override
   4873         protected int[] onCreateDrawableState(int extraSpace) {
   4874             return DEFAULT_PARENT_STATE_SET;
   4875         }
   4876 
   4877         @Override
   4878         public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
   4879             return false;
   4880         }
   4881 
   4882         public void reset() {
   4883             mHasRequestLayout = false;
   4884             mHasCreateContextMenu = false;
   4885             mHasShowContextMenuForChild = false;
   4886             mHasShowContextMenuForChildXY = false;
   4887             mHasChildDrawableStateChanged = false;
   4888             mHasBroughtChildToFront = false;
   4889         }
   4890 
   4891         @Override
   4892         public void childHasTransientStateChanged(View child, boolean hasTransientState) {
   4893 
   4894         }
   4895 
   4896         @Override
   4897         public ViewParent getParentForAccessibility() {
   4898             return null;
   4899         }
   4900 
   4901         @Override
   4902         public void notifySubtreeAccessibilityStateChanged(View child,
   4903             View source, int changeType) {
   4904 
   4905         }
   4906 
   4907         @Override
   4908         public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
   4909             return false;
   4910         }
   4911 
   4912         @Override
   4913         public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
   4914         }
   4915 
   4916         @Override
   4917         public void onStopNestedScroll(View target) {
   4918         }
   4919 
   4920         @Override
   4921         public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
   4922                                    int dxUnconsumed, int dyUnconsumed) {
   4923         }
   4924 
   4925         @Override
   4926         public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
   4927         }
   4928 
   4929         @Override
   4930         public boolean onNestedFling(View target, float velocityX, float velocityY,
   4931                 boolean consumed) {
   4932             return false;
   4933         }
   4934 
   4935         @Override
   4936         public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
   4937             return false;
   4938         }
   4939 
   4940         @Override
   4941         public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
   4942             return false;
   4943         }
   4944     }
   4945 
   4946     private static class MockViewGroupParent extends ViewGroup implements ViewParent {
   4947         private boolean mHasRequestChildRectangleOnScreen = false;
   4948         private Rect mLastRequestedChildRectOnScreen = new Rect(
   4949                 Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
   4950 
   4951         public MockViewGroupParent(Context context) {
   4952             super(context);
   4953         }
   4954 
   4955         @Override
   4956         protected void onLayout(boolean changed, int l, int t, int r, int b) {
   4957 
   4958         }
   4959 
   4960         @Override
   4961         public boolean requestChildRectangleOnScreen(View child,
   4962                 Rect rectangle, boolean immediate) {
   4963             mHasRequestChildRectangleOnScreen = true;
   4964             mLastRequestedChildRectOnScreen.set(rectangle);
   4965             return super.requestChildRectangleOnScreen(child, rectangle, immediate);
   4966         }
   4967 
   4968         public Rect getLastRequestedChildRectOnScreen() {
   4969             return mLastRequestedChildRectOnScreen;
   4970         }
   4971 
   4972         public boolean hasRequestChildRectangleOnScreen() {
   4973             return mHasRequestChildRectangleOnScreen;
   4974         }
   4975 
   4976         @Override
   4977         protected void detachViewFromParent(View child) {
   4978             super.detachViewFromParent(child);
   4979         }
   4980 
   4981         public void reset() {
   4982             mHasRequestChildRectangleOnScreen = false;
   4983         }
   4984     }
   4985 
   4986     private static final class ViewData {
   4987         public int childCount;
   4988         public String tag;
   4989         public View firstChild;
   4990     }
   4991 
   4992     private static class MockUnhandledKeyListener implements OnUnhandledKeyEventListener {
   4993         public View mLastView = null;
   4994         public boolean mGotUp = false;
   4995         public boolean mReturnVal = false;
   4996 
   4997         @Override
   4998         public boolean onUnhandledKeyEvent(View v, KeyEvent event) {
   4999             if (event.getAction() == KeyEvent.ACTION_DOWN) {
   5000                 mLastView = v;
   5001             } else if (event.getAction() == KeyEvent.ACTION_UP) {
   5002                 mGotUp = true;
   5003             }
   5004             return mReturnVal;
   5005         }
   5006         public void reset() {
   5007             mLastView = null;
   5008             mGotUp = false;
   5009         }
   5010         public boolean fired() {
   5011             return mLastView != null && mGotUp;
   5012         }
   5013     }
   5014 
   5015     private static final Class<?> ASYNC_INFLATE_VIEWS[] = {
   5016         android.app.FragmentBreadCrumbs.class,
   5017 // DISABLED because it doesn't have a AppWidgetHostView(Context, AttributeSet)
   5018 // constructor, so it's not inflate-able
   5019 //        android.appwidget.AppWidgetHostView.class,
   5020         android.gesture.GestureOverlayView.class,
   5021         android.inputmethodservice.ExtractEditText.class,
   5022         android.inputmethodservice.KeyboardView.class,
   5023 //        android.media.tv.TvView.class,
   5024 //        android.opengl.GLSurfaceView.class,
   5025 //        android.view.SurfaceView.class,
   5026         android.view.TextureView.class,
   5027         android.view.ViewStub.class,
   5028 //        android.webkit.WebView.class,
   5029         android.widget.AbsoluteLayout.class,
   5030         android.widget.AdapterViewFlipper.class,
   5031         android.widget.AnalogClock.class,
   5032         android.widget.AutoCompleteTextView.class,
   5033         android.widget.Button.class,
   5034         android.widget.CalendarView.class,
   5035         android.widget.CheckBox.class,
   5036         android.widget.CheckedTextView.class,
   5037         android.widget.Chronometer.class,
   5038         android.widget.DatePicker.class,
   5039         android.widget.DialerFilter.class,
   5040         android.widget.DigitalClock.class,
   5041         android.widget.EditText.class,
   5042         android.widget.ExpandableListView.class,
   5043         android.widget.FrameLayout.class,
   5044         android.widget.Gallery.class,
   5045         android.widget.GridView.class,
   5046         android.widget.HorizontalScrollView.class,
   5047         android.widget.ImageButton.class,
   5048         android.widget.ImageSwitcher.class,
   5049         android.widget.ImageView.class,
   5050         android.widget.LinearLayout.class,
   5051         android.widget.ListView.class,
   5052         android.widget.MediaController.class,
   5053         android.widget.MultiAutoCompleteTextView.class,
   5054         android.widget.NumberPicker.class,
   5055         android.widget.ProgressBar.class,
   5056         android.widget.QuickContactBadge.class,
   5057         android.widget.RadioButton.class,
   5058         android.widget.RadioGroup.class,
   5059         android.widget.RatingBar.class,
   5060         android.widget.RelativeLayout.class,
   5061         android.widget.ScrollView.class,
   5062         android.widget.SeekBar.class,
   5063 // DISABLED because it has required attributes
   5064 //        android.widget.SlidingDrawer.class,
   5065         android.widget.Spinner.class,
   5066         android.widget.StackView.class,
   5067         android.widget.Switch.class,
   5068         android.widget.TabHost.class,
   5069         android.widget.TabWidget.class,
   5070         android.widget.TableLayout.class,
   5071         android.widget.TableRow.class,
   5072         android.widget.TextClock.class,
   5073         android.widget.TextSwitcher.class,
   5074         android.widget.TextView.class,
   5075         android.widget.TimePicker.class,
   5076         android.widget.ToggleButton.class,
   5077         android.widget.TwoLineListItem.class,
   5078 //        android.widget.VideoView.class,
   5079         android.widget.ViewAnimator.class,
   5080         android.widget.ViewFlipper.class,
   5081         android.widget.ViewSwitcher.class,
   5082         android.widget.ZoomButton.class,
   5083         android.widget.ZoomControls.class,
   5084     };
   5085 }
   5086