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