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