1 /*
2  * Copyright (C) 2018 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.assertNull;
23 import static org.junit.Assert.assertSame;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
26 import static org.mockito.ArgumentMatchers.any;
27 import static org.mockito.ArgumentMatchers.eq;
28 import static org.mockito.Mockito.inOrder;
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.spy;
31 import static org.mockito.Mockito.times;
32 import static org.mockito.Mockito.verify;
33 import static org.mockito.Mockito.when;
34 
35 import android.app.Activity;
36 import android.content.Context;
37 import android.content.Intent;
38 import android.content.pm.PackageManager;
39 import android.content.res.XmlResourceParser;
40 import android.graphics.Bitmap;
41 import android.graphics.Bitmap.Config;
42 import android.graphics.Canvas;
43 import android.graphics.Insets;
44 import android.graphics.Point;
45 import android.graphics.Rect;
46 import android.graphics.Region;
47 import android.graphics.drawable.BitmapDrawable;
48 import android.os.Parcelable;
49 import android.os.SystemClock;
50 import android.util.AttributeSet;
51 import android.util.DisplayMetrics;
52 import android.util.SparseArray;
53 import android.view.ActionMode;
54 import android.view.Display;
55 import android.view.KeyEvent;
56 import android.view.Menu;
57 import android.view.MenuInflater;
58 import android.view.MenuItem;
59 import android.view.MotionEvent;
60 import android.view.PointerIcon;
61 import android.view.View;
62 import android.view.View.BaseSavedState;
63 import android.view.View.MeasureSpec;
64 import android.view.View.OnApplyWindowInsetsListener;
65 import android.view.ViewGroup;
66 import android.view.ViewGroup.LayoutParams;
67 import android.view.WindowInsets;
68 import android.view.WindowManager;
69 import android.view.animation.AlphaAnimation;
70 import android.view.animation.Animation;
71 import android.view.animation.Animation.AnimationListener;
72 import android.view.animation.LayoutAnimationController;
73 import android.view.animation.RotateAnimation;
74 import android.view.animation.Transformation;
75 import android.view.cts.util.EventUtils;
76 import android.view.cts.util.ScrollBarUtils;
77 import android.view.cts.util.XmlUtils;
78 import android.widget.Button;
79 import android.widget.TextView;
80 
81 import androidx.annotation.NonNull;
82 import androidx.test.InstrumentationRegistry;
83 import androidx.test.annotation.UiThreadTest;
84 import androidx.test.filters.LargeTest;
85 import androidx.test.filters.MediumTest;
86 import androidx.test.rule.ActivityTestRule;
87 import androidx.test.runner.AndroidJUnit4;
88 
89 import com.android.compatibility.common.util.CTSResult;
90 
91 import org.junit.Before;
92 import org.junit.Ignore;
93 import org.junit.Rule;
94 import org.junit.Test;
95 import org.junit.runner.RunWith;
96 import org.mockito.InOrder;
97 
98 import java.util.ArrayList;
99 
100 @MediumTest
101 @RunWith(AndroidJUnit4.class)
102 public class ViewGroupTest implements CTSResult {
103     private Context mContext;
104     private MotionEvent mMotionEvent;
105     private int mResultCode;
106 
107     private MockViewGroup mMockViewGroup;
108     private TextView mTextView;
109     private MockTextView mMockTextView;
110 
111     @Rule
112     public ActivityTestRule<CtsActivity> mCtsActivityRule =
113             new ActivityTestRule<>(CtsActivity.class, false, false);
114 
115     private final Sync mSync = new Sync();
116     private static class Sync {
117         boolean mHasNotify;
118     }
119 
120     @UiThreadTest
121     @Before
setup()122     public void setup() {
123         mContext = InstrumentationRegistry.getTargetContext();
124         mMockViewGroup = new MockViewGroup(mContext);
125         mTextView = new TextView(mContext);
126         mMockTextView = new MockTextView(mContext);
127     }
128 
129     @Test
testConstructor()130     public void testConstructor() {
131         new MockViewGroup(mContext);
132         new MockViewGroup(mContext, null);
133         new MockViewGroup(mContext, null, 0);
134     }
135 
136     @UiThreadTest
137     @Test
testAddFocusables()138     public void testAddFocusables() {
139         mMockViewGroup.setFocusable(true);
140 
141         // Child is focusable.
142         ArrayList<View> list = new ArrayList<>();
143         list.add(mTextView);
144         mMockViewGroup.addView(mTextView);
145         mMockViewGroup.addFocusables(list, 0);
146 
147         assertEquals(2, list.size());
148 
149         // Parent blocks descendants.
150         list = new ArrayList<>();
151         list.add(mTextView);
152         mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
153         mMockViewGroup.setFocusable(false);
154         mMockViewGroup.addFocusables(list, 0);
155         assertEquals(1, list.size());
156 
157         // Both parent and child are focusable.
158         list.clear();
159         mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
160         mTextView.setFocusable(true);
161         mMockViewGroup.setFocusable(true);
162         mMockViewGroup.addFocusables(list, 0);
163         assertEquals(2, list.size());
164     }
165 
166     @UiThreadTest
167     @Test
testAddKeyboardNavigationClusters()168     public void testAddKeyboardNavigationClusters() {
169         View v1 = new MockView(mContext);
170         v1.setFocusableInTouchMode(true);
171         View v2 = new MockView(mContext);
172         v2.setFocusableInTouchMode(true);
173         mMockViewGroup.addView(v1);
174         mMockViewGroup.addView(v2);
175 
176         // No clusters.
177         ArrayList<View> list = new ArrayList<>();
178         mMockViewGroup.addKeyboardNavigationClusters(list, 0);
179         assertEquals(0, list.size());
180 
181         // A cluster and a non-cluster child.
182         v1.setKeyboardNavigationCluster(true);
183         mMockViewGroup.addKeyboardNavigationClusters(list, 0);
184         assertEquals(1, list.size());
185         assertEquals(v1, list.get(0));
186         list.clear();
187 
188         // Blocking descendants from getting focus also blocks group search.
189         mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
190         mMockViewGroup.addKeyboardNavigationClusters(list, 0);
191         assertEquals(0, list.size());
192         mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
193 
194         // Testing the results ordering.
195         v2.setKeyboardNavigationCluster(true);
196         mMockViewGroup.addKeyboardNavigationClusters(list, 0);
197         assertEquals(2, list.size());
198         assertEquals(v1, list.get(0));
199         assertEquals(v2, list.get(1));
200         list.clear();
201 
202         // 3-level hierarchy.
203         ViewGroup parent = new MockViewGroup(mContext);
204         parent.addView(mMockViewGroup);
205         mMockViewGroup.removeView(v2);
206         parent.addKeyboardNavigationClusters(list, 0);
207         assertEquals(1, list.size());
208         assertEquals(v1, list.get(0));
209         list.clear();
210 
211         // Cluster with no focusables gets ignored
212         mMockViewGroup.addView(v2);
213         v2.setFocusable(false);
214         mMockViewGroup.addKeyboardNavigationClusters(list, 0);
215         assertEquals(1, list.size());
216         list.clear();
217 
218         // Invisible children get ignored.
219         mMockViewGroup.setVisibility(View.GONE);
220         parent.addKeyboardNavigationClusters(list, 0);
221         assertEquals(0, list.size());
222         list.clear();
223 
224         // Nested clusters are ignored
225         TestClusterHier h = new TestClusterHier();
226         h.nestedGroup.setKeyboardNavigationCluster(true);
227         h.cluster2.setKeyboardNavigationCluster(false);
228         h.top.addKeyboardNavigationClusters(list, View.FOCUS_FORWARD);
229         assertTrue(list.contains(h.nestedGroup));
230         list.clear();
231         h.cluster2.setKeyboardNavigationCluster(true);
232         h.top.addKeyboardNavigationClusters(list, View.FOCUS_FORWARD);
233         assertFalse(list.contains(h.nestedGroup));
234         list.clear();
235     }
236 
237     @UiThreadTest
238     @Test
testAddStatesFromChildren()239     public void testAddStatesFromChildren() {
240         mMockViewGroup.addView(mTextView);
241         assertFalse(mMockViewGroup.addStatesFromChildren());
242 
243         mMockViewGroup.setAddStatesFromChildren(true);
244         mTextView.performClick();
245         assertTrue(mMockViewGroup.addStatesFromChildren());
246         assertTrue(mMockViewGroup.isDrawableStateChangedCalled);
247     }
248 
249     @UiThreadTest
250     @Test
testAddTouchables()251     public void testAddTouchables() {
252         mMockViewGroup.setFocusable(true);
253 
254         ArrayList<View> list = new ArrayList<>();
255         mTextView.setVisibility(View.VISIBLE);
256         mTextView.setClickable(true);
257         mTextView.setEnabled(true);
258 
259         list.add(mTextView);
260         mMockViewGroup.addView(mTextView);
261         mMockViewGroup.addTouchables(list);
262 
263         assertEquals(2, list.size());
264 
265         View v = mMockViewGroup.getChildAt(0);
266         assertSame(mTextView, v);
267 
268         v = mMockViewGroup.getChildAt(-1);
269         assertNull(v);
270 
271         v = mMockViewGroup.getChildAt(1);
272         assertNull(v);
273 
274         v = mMockViewGroup.getChildAt(100);
275         assertNull(v);
276 
277         v = mMockViewGroup.getChildAt(-100);
278         assertNull(v);
279     }
280 
281     @UiThreadTest
282     @Test
testAddView()283     public void testAddView() {
284         assertEquals(0, mMockViewGroup.getChildCount());
285 
286         mMockViewGroup.addView(mTextView);
287         assertEquals(1, mMockViewGroup.getChildCount());
288         assertTrue(mMockViewGroup.isOnViewAddedCalled);
289     }
290 
291     @UiThreadTest
292     @Test
testAddViewWithParaViewInt()293     public void testAddViewWithParaViewInt() {
294         assertEquals(0, mMockViewGroup.getChildCount());
295 
296         mMockViewGroup.addView(mTextView, -1);
297         assertEquals(1, mMockViewGroup.getChildCount());
298         assertTrue(mMockViewGroup.isOnViewAddedCalled);
299     }
300 
301     @UiThreadTest
302     @Test
testAddViewWithParaViewLayoutPara()303     public void testAddViewWithParaViewLayoutPara() {
304         assertEquals(0, mMockViewGroup.getChildCount());
305 
306         mMockViewGroup.addView(mTextView, new ViewGroup.LayoutParams(100, 200));
307 
308         assertEquals(1, mMockViewGroup.getChildCount());
309         assertTrue(mMockViewGroup.isOnViewAddedCalled);
310     }
311 
312     @UiThreadTest
313     @Test
testAddViewWithParaViewIntInt()314     public void testAddViewWithParaViewIntInt() {
315         final int width = 100;
316         final int height = 200;
317 
318         assertEquals(0, mMockViewGroup.getChildCount());
319 
320         mMockViewGroup.addView(mTextView, width, height);
321         assertEquals(width, mTextView.getLayoutParams().width);
322         assertEquals(height, mTextView.getLayoutParams().height);
323 
324         assertEquals(1, mMockViewGroup.getChildCount());
325         assertTrue(mMockViewGroup.isOnViewAddedCalled);
326     }
327 
328     @UiThreadTest
329     @Test
testAddViewWidthParaViewIntLayoutParam()330     public void testAddViewWidthParaViewIntLayoutParam() {
331         assertEquals(0, mMockViewGroup.getChildCount());
332 
333         mMockViewGroup.addView(mTextView, -1, new ViewGroup.LayoutParams(100, 200));
334 
335         assertEquals(1, mMockViewGroup.getChildCount());
336         assertTrue(mMockViewGroup.isOnViewAddedCalled);
337     }
338 
339     @UiThreadTest
340     @Test
testAddViewInLayout()341     public void testAddViewInLayout() {
342         assertEquals(0, mMockViewGroup.getChildCount());
343 
344         assertTrue(mMockViewGroup.isRequestLayoutCalled);
345         mMockViewGroup.isRequestLayoutCalled = false;
346         assertTrue(mMockViewGroup.addViewInLayout(
347                 mTextView, -1, new ViewGroup.LayoutParams(100, 200)));
348         assertEquals(1, mMockViewGroup.getChildCount());
349         // check that calling addViewInLayout() does not trigger a
350         // requestLayout() on this ViewGroup
351         assertFalse(mMockViewGroup.isRequestLayoutCalled);
352         assertTrue(mMockViewGroup.isOnViewAddedCalled);
353     }
354 
355     @UiThreadTest
356     @Test
testAttachLayoutAnimationParameters()357     public void testAttachLayoutAnimationParameters() {
358         ViewGroup.LayoutParams param = new ViewGroup.LayoutParams(10, 10);
359 
360         mMockViewGroup.attachLayoutAnimationParameters(null, param, 1, 2);
361         assertEquals(2, param.layoutAnimationParameters.count);
362         assertEquals(1, param.layoutAnimationParameters.index);
363     }
364 
365     @UiThreadTest
366     @Test
testAttachViewToParent()367     public void testAttachViewToParent() {
368         mMockViewGroup.setFocusable(true);
369         assertEquals(0, mMockViewGroup.getChildCount());
370 
371         ViewGroup.LayoutParams param = new ViewGroup.LayoutParams(10, 10);
372 
373         mTextView.setFocusable(true);
374         mMockViewGroup.attachViewToParent(mTextView, -1, param);
375         assertSame(mMockViewGroup, mTextView.getParent());
376         assertEquals(1, mMockViewGroup.getChildCount());
377         assertSame(mTextView, mMockViewGroup.getChildAt(0));
378     }
379 
380     @UiThreadTest
381     @Test
testAddViewInLayoutWithParamViewIntLayB()382     public void testAddViewInLayoutWithParamViewIntLayB() {
383         assertEquals(0, mMockViewGroup.getChildCount());
384 
385         assertTrue(mMockViewGroup.isRequestLayoutCalled);
386         mMockViewGroup.isRequestLayoutCalled = false;
387         assertTrue(mMockViewGroup.addViewInLayout(
388                 mTextView, -1, new ViewGroup.LayoutParams(100, 200), true));
389 
390         assertEquals(1, mMockViewGroup.getChildCount());
391         // check that calling addViewInLayout() does not trigger a
392         // requestLayout() on this ViewGroup
393         assertFalse(mMockViewGroup.isRequestLayoutCalled);
394         assertTrue(mMockViewGroup.isOnViewAddedCalled);
395     }
396 
397     @UiThreadTest
398     @Test
testBringChildToFront()399     public void testBringChildToFront() {
400         TextView textView1 = new TextView(mContext);
401         TextView textView2 = new TextView(mContext);
402 
403         assertEquals(0, mMockViewGroup.getChildCount());
404 
405         mMockViewGroup.addView(textView1);
406         mMockViewGroup.addView(textView2);
407         assertEquals(2, mMockViewGroup.getChildCount());
408 
409         mMockViewGroup.bringChildToFront(textView1);
410         assertEquals(mMockViewGroup, textView1.getParent());
411         assertEquals(2, mMockViewGroup.getChildCount());
412         assertNotNull(mMockViewGroup.getChildAt(0));
413         assertSame(textView2, mMockViewGroup.getChildAt(0));
414 
415         mMockViewGroup.bringChildToFront(textView2);
416         assertEquals(mMockViewGroup, textView2.getParent());
417         assertEquals(2, mMockViewGroup.getChildCount());
418         assertNotNull(mMockViewGroup.getChildAt(0));
419         assertSame(textView1, mMockViewGroup.getChildAt(0));
420     }
421 
422     @UiThreadTest
423     @Test
testCanAnimate()424     public void testCanAnimate() {
425         assertFalse(mMockViewGroup.canAnimate());
426 
427         RotateAnimation animation = new RotateAnimation(0.1f, 0.1f);
428         LayoutAnimationController la = new LayoutAnimationController(animation);
429         mMockViewGroup.setLayoutAnimation(la);
430         assertTrue(mMockViewGroup.canAnimate());
431     }
432 
433     @UiThreadTest
434     @Test
testCheckLayoutParams()435     public void testCheckLayoutParams() {
436         assertFalse(mMockViewGroup.checkLayoutParams(null));
437 
438         assertTrue(mMockViewGroup.checkLayoutParams(new ViewGroup.LayoutParams(100, 200)));
439     }
440 
441     @UiThreadTest
442     @Test
testChildDrawableStateChanged()443     public void testChildDrawableStateChanged() {
444         mMockViewGroup.setAddStatesFromChildren(true);
445 
446         mMockViewGroup.childDrawableStateChanged(null);
447         assertTrue(mMockViewGroup.isRefreshDrawableStateCalled);
448     }
449 
450     @UiThreadTest
451     @Test
testCleanupLayoutState()452     public void testCleanupLayoutState() {
453         assertTrue(mTextView.isLayoutRequested());
454 
455         mMockViewGroup.cleanupLayoutState(mTextView);
456         assertFalse(mTextView.isLayoutRequested());
457     }
458 
459     @UiThreadTest
460     @Test
testClearChildFocus()461     public void testClearChildFocus() {
462         mMockViewGroup.addView(mTextView);
463         mMockViewGroup.requestChildFocus(mTextView, null);
464 
465         View focusedView = mMockViewGroup.getFocusedChild();
466         assertSame(mTextView, focusedView);
467 
468         mMockViewGroup.clearChildFocus(mTextView);
469         assertNull(mMockViewGroup.getFocusedChild());
470     }
471 
472     @UiThreadTest
473     @Test
testClearDisappearingChildren()474     public void testClearDisappearingChildren() {
475         Canvas canvas = new Canvas();
476         MockViewGroup child = new MockViewGroup(mContext);
477         child.setAnimation(new MockAnimation());
478         mMockViewGroup.addView(child);
479         assertEquals(1, mMockViewGroup.getChildCount());
480 
481         assertNotNull(child.getAnimation());
482         mMockViewGroup.dispatchDraw(canvas);
483         assertEquals(1, mMockViewGroup.drawChildCalledTime);
484 
485         child.setAnimation(new MockAnimation());
486         mMockViewGroup.removeAllViewsInLayout();
487 
488         mMockViewGroup.drawChildCalledTime = 0;
489         mMockViewGroup.dispatchDraw(canvas);
490         assertEquals(1, mMockViewGroup.drawChildCalledTime);
491 
492         child.setAnimation(new MockAnimation());
493         mMockViewGroup.clearDisappearingChildren();
494 
495         mMockViewGroup.drawChildCalledTime = 0;
496         mMockViewGroup.dispatchDraw(canvas);
497         assertEquals(0, mMockViewGroup.drawChildCalledTime);
498     }
499 
500     @UiThreadTest
501     @Test
testClearFocus()502     public void testClearFocus() {
503         mMockViewGroup.addView(mMockTextView);
504         mMockViewGroup.requestChildFocus(mMockTextView, null);
505         mMockViewGroup.clearFocus();
506         assertTrue(mMockTextView.isClearFocusCalled);
507     }
508 
509     @UiThreadTest
510     @Test
testDetachAllViewsFromParent()511     public void testDetachAllViewsFromParent() {
512         mMockViewGroup.addView(mTextView);
513         assertEquals(1, mMockViewGroup.getChildCount());
514         assertSame(mMockViewGroup, mTextView.getParent());
515         mMockViewGroup.detachAllViewsFromParent();
516         assertEquals(0, mMockViewGroup.getChildCount());
517         assertNull(mTextView.getParent());
518     }
519 
520     @UiThreadTest
521     @Test
testDetachViewFromParent()522     public void testDetachViewFromParent() {
523         mMockViewGroup.addView(mTextView);
524         assertEquals(1, mMockViewGroup.getChildCount());
525 
526         mMockViewGroup.detachViewFromParent(0);
527 
528         assertEquals(0, mMockViewGroup.getChildCount());
529         assertNull(mTextView.getParent());
530     }
531 
532     @UiThreadTest
533     @Test
testDetachViewFromParentWithParamView()534     public void testDetachViewFromParentWithParamView() {
535         mMockViewGroup.addView(mTextView);
536         assertEquals(1, mMockViewGroup.getChildCount());
537         assertSame(mMockViewGroup, mTextView.getParent());
538 
539         mMockViewGroup.detachViewFromParent(mTextView);
540 
541         assertEquals(0, mMockViewGroup.getChildCount());
542         assertNull(mMockViewGroup.getParent());
543     }
544 
545     @UiThreadTest
546     @Test
testDetachViewsFromParent()547     public void testDetachViewsFromParent() {
548         TextView textView1 = new TextView(mContext);
549         TextView textView2 = new TextView(mContext);
550         TextView textView3 = new TextView(mContext);
551 
552         mMockViewGroup.addView(textView1);
553         mMockViewGroup.addView(textView2);
554         mMockViewGroup.addView(textView3);
555         assertEquals(3, mMockViewGroup.getChildCount());
556 
557         mMockViewGroup.detachViewsFromParent(0, 2);
558 
559         assertEquals(1, mMockViewGroup.getChildCount());
560         assertNull(textView1.getParent());
561         assertNull(textView2.getParent());
562     }
563 
564     @UiThreadTest
565     @Test
testDispatchDraw()566     public void testDispatchDraw() {
567         Canvas canvas = new Canvas();
568 
569         mMockViewGroup.draw(canvas);
570         assertTrue(mMockViewGroup.isDispatchDrawCalled);
571         assertSame(canvas, mMockViewGroup.canvas);
572     }
573 
574     @UiThreadTest
575     @Test
testDispatchFreezeSelfOnly()576     public void testDispatchFreezeSelfOnly() {
577         mMockViewGroup.setId(1);
578         mMockViewGroup.setSaveEnabled(true);
579 
580         SparseArray container = new SparseArray();
581         assertEquals(0, container.size());
582         mMockViewGroup.dispatchFreezeSelfOnly(container);
583         assertEquals(1, container.size());
584     }
585 
586     @UiThreadTest
587     @Test
testDispatchKeyEvent()588     public void testDispatchKeyEvent() {
589         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
590         assertFalse(mMockViewGroup.dispatchKeyEvent(event));
591 
592         mMockViewGroup.addView(mMockTextView);
593         mMockViewGroup.requestChildFocus(mMockTextView, null);
594         mMockTextView.layout(1, 1, 100, 100);
595 
596         assertTrue(mMockViewGroup.dispatchKeyEvent(event));
597     }
598 
599     @UiThreadTest
600     @Test
testDispatchSaveInstanceState()601     public void testDispatchSaveInstanceState() {
602         mMockViewGroup.setId(2);
603         mMockViewGroup.setSaveEnabled(true);
604         mMockTextView.setSaveEnabled(true);
605         mMockTextView.setId(1);
606         mMockViewGroup.addView(mMockTextView);
607 
608         SparseArray array = new SparseArray();
609         mMockViewGroup.dispatchSaveInstanceState(array);
610 
611         assertTrue(array.size() > 0);
612         assertNotNull(array.get(2));
613 
614         array = new SparseArray();
615         mMockViewGroup.dispatchRestoreInstanceState(array);
616         assertTrue(mMockTextView.isDispatchRestoreInstanceStateCalled);
617     }
618 
619     @UiThreadTest
620     @Test
testDispatchSetPressed()621     public void testDispatchSetPressed() {
622         mMockViewGroup.addView(mMockTextView);
623 
624         mMockViewGroup.dispatchSetPressed(true);
625         assertTrue(mMockTextView.isPressed());
626 
627         mMockViewGroup.dispatchSetPressed(false);
628         assertFalse(mMockTextView.isPressed());
629     }
630 
631     @UiThreadTest
632     @Test
testDispatchSetSelected()633     public void testDispatchSetSelected() {
634         mMockViewGroup.addView(mMockTextView);
635 
636         mMockViewGroup.dispatchSetSelected(true);
637         assertTrue(mMockTextView.isSelected());
638 
639         mMockViewGroup.dispatchSetSelected(false);
640         assertFalse(mMockTextView.isSelected());
641     }
642 
643     @UiThreadTest
644     @Test
testDispatchThawSelfOnly()645     public void testDispatchThawSelfOnly() {
646         mMockViewGroup.setId(1);
647         SparseArray array = new SparseArray();
648         array.put(1, BaseSavedState.EMPTY_STATE);
649 
650         mMockViewGroup.dispatchThawSelfOnly(array);
651         assertTrue(mMockViewGroup.isOnRestoreInstanceStateCalled);
652     }
653 
654     @UiThreadTest
655     @Test
testDispatchTouchEvent()656     public void testDispatchTouchEvent() {
657         DisplayMetrics metrics = new DisplayMetrics();
658         WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
659         Display d = wm.getDefaultDisplay();
660         d.getMetrics(metrics);
661         int screenWidth = metrics.widthPixels;
662         int screenHeight = metrics.heightPixels;
663         mMockViewGroup.layout(0, 0, screenWidth, screenHeight);
664         mMockViewGroup.setLayoutParams(new ViewGroup.LayoutParams(screenWidth, screenHeight));
665 
666         mMotionEvent = null;
667         mMockTextView.setOnTouchListener((View v, MotionEvent event) -> {
668             mMotionEvent = event;
669             return true;
670         });
671 
672         mMockTextView.setVisibility(View.VISIBLE);
673         mMockTextView.setEnabled(true);
674 
675         mMockViewGroup.addView(mMockTextView, new LayoutParams(screenWidth, screenHeight));
676 
677         mMockViewGroup.requestDisallowInterceptTouchEvent(true);
678         MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(),
679                 SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN,
680                 screenWidth / 2, screenHeight / 2, 0);
681 
682         assertFalse(mMockViewGroup.dispatchTouchEvent(me));
683         assertNull(mMotionEvent);
684 
685         mMockTextView.layout(0, 0, screenWidth, screenHeight);
686         assertTrue(mMockViewGroup.dispatchTouchEvent(me));
687         assertSame(me, mMotionEvent);
688     }
689 
690     @UiThreadTest
691     @Test
testDispatchTrackballEvent()692     public void testDispatchTrackballEvent() {
693         MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(),
694                 SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 100, 100,
695                 0);
696         assertFalse(mMockViewGroup.dispatchTrackballEvent(me));
697 
698         mMockViewGroup.addView(mMockTextView);
699         mMockTextView.layout(1, 1, 100, 100);
700         mMockViewGroup.requestChildFocus(mMockTextView, null);
701         assertTrue(mMockViewGroup.dispatchTrackballEvent(me));
702     }
703 
704     @UiThreadTest
705     @Test
testDispatchUnhandledMove()706     public void testDispatchUnhandledMove() {
707         assertFalse(mMockViewGroup.dispatchUnhandledMove(mMockTextView, View.FOCUS_DOWN));
708 
709         mMockViewGroup.addView(mMockTextView);
710         mMockTextView.layout(1, 1, 100, 100);
711         mMockViewGroup.requestChildFocus(mMockTextView, null);
712         assertTrue(mMockViewGroup.dispatchUnhandledMove(mMockTextView, View.FOCUS_DOWN));
713     }
714 
715     @UiThreadTest
716     @Test
testDispatchWindowFocusChanged()717     public void testDispatchWindowFocusChanged() {
718         mMockViewGroup.addView(mMockTextView);
719         mMockTextView.setPressed(true);
720         assertTrue(mMockTextView.isPressed());
721 
722         mMockViewGroup.dispatchWindowFocusChanged(false);
723         assertFalse(mMockTextView.isPressed());
724     }
725 
726     @UiThreadTest
727     @Test
testDispatchWindowVisibilityChanged()728     public void testDispatchWindowVisibilityChanged() {
729         int expected = 10;
730 
731         mMockViewGroup.addView(mMockTextView);
732         mMockViewGroup.dispatchWindowVisibilityChanged(expected);
733         assertEquals(expected, mMockTextView.visibility);
734     }
735 
736     @UiThreadTest
737     @Test
testDrawableStateChanged()738     public void testDrawableStateChanged() {
739         mMockTextView.setDuplicateParentStateEnabled(true);
740 
741         mMockViewGroup.addView(mMockTextView);
742         mMockViewGroup.setAddStatesFromChildren(false);
743         mMockViewGroup.drawableStateChanged();
744         assertTrue(mMockTextView.mIsRefreshDrawableStateCalled);
745     }
746 
747     @UiThreadTest
748     @Test
testDrawChild()749     public void testDrawChild() {
750         mMockViewGroup.addView(mMockTextView);
751 
752         MockCanvas canvas = new MockCanvas();
753         mMockTextView.setBackgroundDrawable(new BitmapDrawable(Bitmap.createBitmap(100, 100,
754                 Config.ALPHA_8)));
755         assertFalse(mMockViewGroup.drawChild(canvas, mMockTextView, 100));
756         // test whether child's draw method is called.
757         assertTrue(mMockTextView.isDrawCalled);
758     }
759 
760     @UiThreadTest
761     @Test
testFindFocus()762     public void testFindFocus() {
763         assertNull(mMockViewGroup.findFocus());
764         mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
765         mMockViewGroup.setFocusable(true);
766         mMockViewGroup.setVisibility(View.VISIBLE);
767         mMockViewGroup.setFocusableInTouchMode(true);
768         assertTrue(mMockViewGroup.requestFocus(1, new Rect()));
769 
770         assertSame(mMockViewGroup, mMockViewGroup.findFocus());
771     }
772 
773     static class MockView extends ViewGroup {
774 
775         public int mWidthMeasureSpec;
776         public int mHeightMeasureSpec;
777 
MockView(Context context)778         public MockView(Context context) {
779             super(context);
780         }
781 
782         @Override
onLayout(boolean changed, int l, int t, int r, int b)783         public void onLayout(boolean changed, int l, int t, int r, int b) {
784         }
785 
786         @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)787         public void onMeasure(int widthMeasureSpec,
788                 int heightMeasureSpec) {
789             mWidthMeasureSpec = widthMeasureSpec;
790             mHeightMeasureSpec = heightMeasureSpec;
791             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
792         }
793     }
794 
795     @UiThreadTest
796     @Test
testFocusableViewAvailable()797     public void testFocusableViewAvailable() {
798         MockView child = new MockView(mContext);
799         mMockViewGroup.addView(child);
800 
801         child.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
802         child.focusableViewAvailable(mMockViewGroup);
803 
804         assertTrue(mMockViewGroup.isFocusableViewAvailable);
805     }
806 
807     @UiThreadTest
808     @Test
testFocusSearch()809     public void testFocusSearch() {
810         MockView child = new MockView(mContext);
811         mMockViewGroup.addView(child);
812         child.addView(mMockTextView);
813         assertSame(mMockTextView, child.focusSearch(mMockTextView, 1));
814     }
815 
816     @UiThreadTest
817     @Test
testGatherTransparentRegion()818     public void testGatherTransparentRegion() {
819         Region region = new Region();
820         mMockTextView.setAnimation(new AlphaAnimation(mContext, null));
821         mMockTextView.setVisibility(100);
822         mMockViewGroup.addView(mMockTextView);
823         assertEquals(1, mMockViewGroup.getChildCount());
824 
825         assertTrue(mMockViewGroup.gatherTransparentRegion(region));
826         assertTrue(mMockViewGroup.gatherTransparentRegion(null));
827     }
828 
829     @UiThreadTest
830     @Test
testGenerateDefaultLayoutParams()831     public void testGenerateDefaultLayoutParams(){
832         LayoutParams lp = mMockViewGroup.generateDefaultLayoutParams();
833 
834         assertEquals(LayoutParams.WRAP_CONTENT, lp.width);
835         assertEquals(LayoutParams.WRAP_CONTENT, lp.height);
836     }
837 
838     @UiThreadTest
839     @Test
testGenerateLayoutParamsWithParaAttributeSet()840     public void testGenerateLayoutParamsWithParaAttributeSet() throws Exception {
841         XmlResourceParser set = mContext.getResources().getLayout(
842                 android.view.cts.R.layout.abslistview_layout);
843         XmlUtils.beginDocument(set, "ViewGroup_Layout");
844         LayoutParams lp = mMockViewGroup.generateLayoutParams(set);
845         assertNotNull(lp);
846         assertEquals(25, lp.height);
847         assertEquals(25, lp.width);
848     }
849 
850     @UiThreadTest
851     @Test
testGenerateLayoutParams()852     public void testGenerateLayoutParams() {
853         LayoutParams p = new LayoutParams(LayoutParams.WRAP_CONTENT,
854                 LayoutParams.MATCH_PARENT);
855         LayoutParams generatedParams = mMockViewGroup.generateLayoutParams(p);
856         assertEquals(generatedParams.getClass(), p.getClass());
857         assertEquals(p.width, generatedParams.width);
858         assertEquals(p.height, generatedParams.height);
859     }
860 
861     @UiThreadTest
862     @Test
testGetChildDrawingOrder()863     public void testGetChildDrawingOrder() {
864         assertEquals(1, mMockViewGroup.getChildDrawingOrder(0, 1));
865         assertEquals(2, mMockViewGroup.getChildDrawingOrder(0, 2));
866     }
867 
868     @Test
testGetChildMeasureSpec()869     public void testGetChildMeasureSpec() {
870         int spec = 1;
871         int padding = 1;
872         int childDimension = 1;
873         assertEquals(MeasureSpec.makeMeasureSpec(childDimension, MeasureSpec.EXACTLY),
874                 ViewGroup.getChildMeasureSpec(spec, padding, childDimension));
875         spec = 4;
876         padding = 6;
877         childDimension = 9;
878         assertEquals(MeasureSpec.makeMeasureSpec(childDimension, MeasureSpec.EXACTLY),
879                 ViewGroup.getChildMeasureSpec(spec, padding, childDimension));
880     }
881 
882     @UiThreadTest
883     @Test
testGetChildStaticTransformation()884     public void testGetChildStaticTransformation() {
885         assertFalse(mMockViewGroup.getChildStaticTransformation(null, null));
886     }
887 
888     @UiThreadTest
889     @Test
testGetChildVisibleRect()890     public void testGetChildVisibleRect() {
891         mMockTextView.layout(1, 1, 100, 100);
892         Rect rect = new Rect(1, 1, 50, 50);
893         Point p = new Point();
894         assertFalse(mMockViewGroup.getChildVisibleRect(mMockTextView, rect, p));
895 
896         mMockTextView.layout(0, 0, 0, 0);
897         mMockViewGroup.layout(20, 20, 60, 60);
898         rect = new Rect(10, 10, 40, 40);
899         p = new Point();
900         assertTrue(mMockViewGroup.getChildVisibleRect(mMockTextView, rect, p));
901     }
902 
903     @UiThreadTest
904     @Test
testGetDescendantFocusability()905     public void testGetDescendantFocusability() {
906         final int FLAG_MASK_FOCUSABILITY = 0x60000;
907         assertFalse((mMockViewGroup.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0);
908 
909         mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
910         assertFalse((mMockViewGroup.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0);
911     }
912 
913     @UiThreadTest
914     @Test
testGetLayoutAnimation()915     public void testGetLayoutAnimation() {
916         assertNull(mMockViewGroup.getLayoutAnimation());
917         RotateAnimation animation = new RotateAnimation(0.1f, 0.1f);
918         LayoutAnimationController la = new LayoutAnimationController(animation);
919         mMockViewGroup.setLayoutAnimation(la);
920         assertTrue(mMockViewGroup.canAnimate());
921         assertSame(la, mMockViewGroup.getLayoutAnimation());
922     }
923 
924     @UiThreadTest
925     @Test
testGetLayoutAnimationListener()926     public void testGetLayoutAnimationListener() {
927         assertNull(mMockViewGroup.getLayoutAnimationListener());
928 
929         AnimationListener al = new AnimationListener() {
930             @Override
931             public void onAnimationEnd(Animation animation) {
932             }
933 
934             @Override
935             public void onAnimationRepeat(Animation animation) {
936             }
937 
938             @Override
939             public void onAnimationStart(Animation animation) {
940             }
941         };
942         mMockViewGroup.setLayoutAnimationListener(al);
943         assertSame(al, mMockViewGroup.getLayoutAnimationListener());
944     }
945 
946     @UiThreadTest
947     @Test
testGetPersistentDrawingCache()948     public void testGetPersistentDrawingCache() {
949         final int mPersistentDrawingCache1 = 2;
950         final int mPersistentDrawingCache2 = 3;
951         assertEquals(mPersistentDrawingCache1, mMockViewGroup.getPersistentDrawingCache());
952 
953         mMockViewGroup.setPersistentDrawingCache(mPersistentDrawingCache2);
954         assertEquals(mPersistentDrawingCache2, mMockViewGroup.getPersistentDrawingCache());
955     }
956 
957     @UiThreadTest
958     @Test
testHasFocus()959     public void testHasFocus() {
960         assertFalse(mMockViewGroup.hasFocus());
961 
962         mMockViewGroup.addView(mTextView);
963         mMockViewGroup.requestChildFocus(mTextView, null);
964 
965         assertTrue(mMockViewGroup.hasFocus());
966     }
967 
968     @UiThreadTest
969     @Test
testHasFocusable()970     public void testHasFocusable() {
971         assertFalse(mMockViewGroup.hasFocusable());
972 
973         mMockViewGroup.setVisibility(View.VISIBLE);
974         mMockViewGroup.setFocusable(true);
975         assertTrue(mMockViewGroup.hasFocusable());
976     }
977 
978     @UiThreadTest
979     @Test
testIndexOfChild()980     public void testIndexOfChild() {
981         assertEquals(-1, mMockViewGroup.indexOfChild(mTextView));
982 
983         mMockViewGroup.addView(mTextView);
984         assertEquals(0, mMockViewGroup.indexOfChild(mTextView));
985     }
986 
987     @LargeTest
988     @Test
testInvalidateChild()989     public void testInvalidateChild() {
990         ViewGroupInvalidateChildCtsActivity.setResult(this);
991 
992         Context context = InstrumentationRegistry.getTargetContext();
993         Intent intent = new Intent(context, ViewGroupInvalidateChildCtsActivity.class);
994         intent.setAction(ViewGroupInvalidateChildCtsActivity.ACTION_INVALIDATE_CHILD);
995         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
996         context.startActivity(intent);
997 
998         waitForResult();
999         assertEquals(CTSResult.RESULT_OK, mResultCode);
1000     }
1001 
1002     @Test
onInterceptHoverEvent_verticalCanScroll_intercepts()1003     public void onInterceptHoverEvent_verticalCanScroll_intercepts() {
1004         onInterceptHoverEvent_scrollabilityAffectsResult(true, true, true);
1005     }
1006 
1007     @Test
onInterceptHoverEvent_verticalCantScroll_doesntIntercept()1008     public void onInterceptHoverEvent_verticalCantScroll_doesntIntercept() {
1009         onInterceptHoverEvent_scrollabilityAffectsResult(true, false, false);
1010     }
1011 
1012     @Test
onInterceptHoverEvent_horizontalCanScroll_intercepts()1013     public void onInterceptHoverEvent_horizontalCanScroll_intercepts() {
1014         onInterceptHoverEvent_scrollabilityAffectsResult(false, true, true);
1015     }
1016 
1017     @Test
onInterceptHoverEvent_horizontalCantScroll_doesntIntercept()1018     public void onInterceptHoverEvent_horizontalCantScroll_doesntIntercept() {
1019         onInterceptHoverEvent_scrollabilityAffectsResult(false, false, false);
1020     }
1021 
onInterceptHoverEvent_scrollabilityAffectsResult(boolean vertical, boolean canScroll, boolean intercepts)1022     private void onInterceptHoverEvent_scrollabilityAffectsResult(boolean vertical,
1023             boolean canScroll, boolean intercepts) {
1024 
1025         // Arrange
1026 
1027         int range = canScroll ? 101 : 100;
1028 
1029         final ScrollTestView viewGroup = spy(new ScrollTestView(mContext));
1030         viewGroup.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT);
1031         viewGroup.setHorizontalScrollBarEnabled(true);
1032         viewGroup.setVerticalScrollBarEnabled(true);
1033         viewGroup.setScrollBarSize(10);
1034         viewGroup.layout(0, 0, 100, 100);
1035 
1036         when(viewGroup.computeVerticalScrollExtent()).thenReturn(100);
1037         when(viewGroup.computeVerticalScrollRange()).thenReturn(range);
1038         when(viewGroup.computeHorizontalScrollExtent()).thenReturn(100);
1039         when(viewGroup.computeHorizontalScrollRange()).thenReturn(range);
1040 
1041         int touchX = vertical ? 95 : 50;
1042         int touchY = vertical ? 50 : 95;
1043         MotionEvent event =
1044                 EventUtils.generateMouseEvent(touchX, touchY, MotionEvent.ACTION_HOVER_ENTER, 0);
1045 
1046         // Act
1047 
1048         boolean actualResult = viewGroup.onInterceptHoverEvent(event);
1049         event.recycle();
1050 
1051         // Assert
1052 
1053         assertEquals(actualResult, intercepts);
1054     }
1055 
1056     @Test
onInterceptTouchEvent_verticalCanScroll_intercepts()1057     public void onInterceptTouchEvent_verticalCanScroll_intercepts() {
1058         onInterceptTouchEvent_scrollabilityAffectsResult(true, true, true);
1059     }
1060 
1061     @Test
onInterceptTouchEvent_verticalCantScroll_doesntIntercept()1062     public void onInterceptTouchEvent_verticalCantScroll_doesntIntercept() {
1063         onInterceptTouchEvent_scrollabilityAffectsResult(true, false, false);
1064     }
1065 
1066     @Test
onInterceptTouchEvent_horizontalCanScroll_intercepts()1067     public void onInterceptTouchEvent_horizontalCanScroll_intercepts() {
1068         onInterceptTouchEvent_scrollabilityAffectsResult(false, true, true);
1069     }
1070 
1071     @Test
onInterceptTouchEvent_horizontalCantScroll_doesntIntercept()1072     public void onInterceptTouchEvent_horizontalCantScroll_doesntIntercept() {
1073         onInterceptTouchEvent_scrollabilityAffectsResult(false, false, false);
1074     }
1075 
onInterceptTouchEvent_scrollabilityAffectsResult(boolean vertical, boolean canScroll, boolean intercepts)1076     private void onInterceptTouchEvent_scrollabilityAffectsResult(boolean vertical,
1077             boolean canScroll, boolean intercepts) {
1078         int range = canScroll ? 101 : 100;
1079         int thumbLength = ScrollBarUtils.getThumbLength(1, 10, 100, range);
1080 
1081         PointerIcon expectedPointerIcon = PointerIcon.getSystemIcon(mContext,
1082                 PointerIcon.TYPE_HAND);
1083 
1084         final ScrollTestView viewGroup = spy(new ScrollTestView(mContext));
1085         viewGroup.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT);
1086         viewGroup.setHorizontalScrollBarEnabled(true);
1087         viewGroup.setVerticalScrollBarEnabled(true);
1088         viewGroup.setScrollBarSize(10);
1089         viewGroup.setPointerIcon(expectedPointerIcon);
1090         viewGroup.layout(0, 0, 100, 100);
1091 
1092         when(viewGroup.computeVerticalScrollExtent()).thenReturn(100);
1093         when(viewGroup.computeVerticalScrollRange()).thenReturn(range);
1094         when(viewGroup.computeHorizontalScrollExtent()).thenReturn(100);
1095         when(viewGroup.computeHorizontalScrollRange()).thenReturn(range);
1096 
1097         int touchX = vertical ? 95 : thumbLength / 2;
1098         int touchY = vertical ? thumbLength / 2 : 95;
1099         MotionEvent event = EventUtils.generateMouseEvent(touchX, touchY, MotionEvent.ACTION_DOWN,
1100                 MotionEvent.BUTTON_PRIMARY);
1101 
1102         // Act
1103 
1104         boolean actualResult = viewGroup.onInterceptTouchEvent(event);
1105         event.recycle();
1106 
1107         // Assert
1108 
1109         assertEquals(intercepts, actualResult);
1110     }
1111 
1112     @Test
onResolvePointerIcon_verticalCanScroll_pointerIsArrow()1113     public void onResolvePointerIcon_verticalCanScroll_pointerIsArrow() {
1114         onResolvePointerIcon_scrollabilityAffectsPointerIcon(true, true, true);
1115     }
1116 
1117     @Test
onResolvePointerIcon_verticalCantScroll_pointerIsProperty()1118     public void onResolvePointerIcon_verticalCantScroll_pointerIsProperty() {
1119         onResolvePointerIcon_scrollabilityAffectsPointerIcon(true, false, false);
1120     }
1121 
1122     @Test
onResolvePointerIcon_horizontalCanScroll_pointerIsArrow()1123     public void onResolvePointerIcon_horizontalCanScroll_pointerIsArrow() {
1124         onResolvePointerIcon_scrollabilityAffectsPointerIcon(false, true, true);
1125     }
1126 
1127     @Test
onResolvePointerIcon_horizontalCantScroll_pointerIsProperty()1128     public void onResolvePointerIcon_horizontalCantScroll_pointerIsProperty() {
1129         onResolvePointerIcon_scrollabilityAffectsPointerIcon(false, false, false);
1130     }
1131 
onResolvePointerIcon_scrollabilityAffectsPointerIcon(boolean vertical, boolean canScroll, boolean pointerIsSystemArrow)1132     private void onResolvePointerIcon_scrollabilityAffectsPointerIcon(boolean vertical,
1133             boolean canScroll, boolean pointerIsSystemArrow) {
1134 
1135         // Arrange
1136 
1137         int range = canScroll ? 101 : 100;
1138         int thumbLength = ScrollBarUtils.getThumbLength(1, 10, 100, range);
1139 
1140         PointerIcon expectedPointerIcon = PointerIcon.getSystemIcon(mContext,
1141                 PointerIcon.TYPE_HAND);
1142 
1143         final ScrollTestView viewGroup = spy(new ScrollTestView(mContext));
1144         viewGroup.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT);
1145         viewGroup.setHorizontalScrollBarEnabled(true);
1146         viewGroup.setVerticalScrollBarEnabled(true);
1147         viewGroup.setScrollBarSize(10);
1148         viewGroup.setPointerIcon(expectedPointerIcon);
1149         viewGroup.layout(0, 0, 100, 100);
1150 
1151         when(viewGroup.computeVerticalScrollExtent()).thenReturn(100);
1152         when(viewGroup.computeVerticalScrollRange()).thenReturn(range);
1153         when(viewGroup.computeHorizontalScrollExtent()).thenReturn(100);
1154         when(viewGroup.computeHorizontalScrollRange()).thenReturn(range);
1155 
1156         int touchX = vertical ? 95 : thumbLength / 2;
1157         int touchY = vertical ? thumbLength / 2 : 95;
1158         MotionEvent event =
1159                 EventUtils.generateMouseEvent(touchX, touchY, MotionEvent.ACTION_HOVER_ENTER, 0);
1160 
1161         // Act
1162 
1163         PointerIcon actualResult = viewGroup.onResolvePointerIcon(event, 0);
1164         event.recycle();
1165 
1166         // Assert
1167 
1168         if (pointerIsSystemArrow) {
1169             assertEquals(PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW), actualResult);
1170         } else {
1171             assertEquals(expectedPointerIcon, actualResult);
1172         }
1173     }
1174 
1175 
1176     @Test
testOnDescendantInvalidated()1177     public void testOnDescendantInvalidated() throws Throwable {
1178         Activity activity = null;
1179         try {
1180             activity = mCtsActivityRule.launchActivity(new Intent());
1181 
1182             mCtsActivityRule.runOnUiThread(() -> {
1183                 View child = mTextView;
1184                 MockViewGroup parent = mMockViewGroup;
1185                 MockViewGroup grandParent = new MockViewGroup(mContext);
1186                 parent.addView(child);
1187                 grandParent.addView(parent);
1188                 mCtsActivityRule.getActivity().setContentView(grandParent);
1189 
1190                 parent.isOnDescendantInvalidatedCalled = false;
1191                 grandParent.isOnDescendantInvalidatedCalled = false;
1192 
1193                 parent.invalidateChild(child, new Rect(0, 0, 1, 1));
1194 
1195                 assertTrue(parent.isOnDescendantInvalidatedCalled);
1196                 assertTrue(grandParent.isOnDescendantInvalidatedCalled);
1197 
1198                 parent.isOnDescendantInvalidatedCalled = false;
1199                 grandParent.isOnDescendantInvalidatedCalled = false;
1200 
1201                 grandParent.invalidateChild(child, new Rect(0, 0, 1, 1));
1202 
1203                 assertFalse(parent.isOnDescendantInvalidatedCalled);
1204                 assertTrue(grandParent.isOnDescendantInvalidatedCalled);
1205             });
1206         } finally {
1207             if (activity != null) {
1208                 activity.finish();
1209             }
1210         }
1211     }
1212 
waitForResult()1213     private void waitForResult() {
1214         synchronized (mSync) {
1215             while(!mSync.mHasNotify) {
1216                 try {
1217                     mSync.wait();
1218                 } catch (InterruptedException e) {
1219                 }
1220             }
1221         }
1222     }
1223 
1224     @UiThreadTest
1225     @Test
testIsAlwaysDrawnWithCacheEnabled()1226     public void testIsAlwaysDrawnWithCacheEnabled() {
1227         assertTrue(mMockViewGroup.isAlwaysDrawnWithCacheEnabled());
1228 
1229         mMockViewGroup.setAlwaysDrawnWithCacheEnabled(false);
1230         assertFalse(mMockViewGroup.isAlwaysDrawnWithCacheEnabled());
1231         mMockViewGroup.setAlwaysDrawnWithCacheEnabled(true);
1232         assertTrue(mMockViewGroup.isAlwaysDrawnWithCacheEnabled());
1233     }
1234 
1235     @UiThreadTest
1236     @Test
testIsAnimationCacheEnabled()1237     public void testIsAnimationCacheEnabled() {
1238         assertTrue(mMockViewGroup.isAnimationCacheEnabled());
1239 
1240         mMockViewGroup.setAnimationCacheEnabled(false);
1241         assertFalse(mMockViewGroup.isAnimationCacheEnabled());
1242         mMockViewGroup.setAnimationCacheEnabled(true);
1243         assertTrue(mMockViewGroup.isAnimationCacheEnabled());
1244     }
1245 
1246     @UiThreadTest
1247     @Test
testIsChildrenDrawnWithCacheEnabled()1248     public void testIsChildrenDrawnWithCacheEnabled() {
1249         assertFalse(mMockViewGroup.isChildrenDrawnWithCacheEnabled());
1250 
1251         mMockViewGroup.setChildrenDrawnWithCacheEnabled(true);
1252         assertTrue(mMockViewGroup.isChildrenDrawnWithCacheEnabled());
1253     }
1254 
1255     @UiThreadTest
1256     @Test
testMeasureChild()1257     public void testMeasureChild() {
1258         final int width = 100;
1259         final int height = 200;
1260         MockView child = new MockView(mContext);
1261         child.setLayoutParams(new LayoutParams(width, height));
1262         child.forceLayout();
1263         mMockViewGroup.addView(child);
1264 
1265         final int parentWidthMeasureSpec = 1;
1266         final int parentHeightMeasureSpec = 2;
1267         mMockViewGroup.measureChild(child, parentWidthMeasureSpec, parentHeightMeasureSpec);
1268         assertEquals(ViewGroup.getChildMeasureSpec(parentWidthMeasureSpec, 0, width),
1269                 child.mWidthMeasureSpec);
1270         assertEquals(ViewGroup.getChildMeasureSpec(parentHeightMeasureSpec, 0, height),
1271                 child.mHeightMeasureSpec);
1272     }
1273 
1274     @UiThreadTest
1275     @Test
testMeasureChildren()1276     public void testMeasureChildren() {
1277         final int widthMeasureSpec = 100;
1278         final int heightMeasureSpec = 200;
1279         MockTextView textView1 = new MockTextView(mContext);
1280 
1281         mMockViewGroup.addView(textView1);
1282         mMockViewGroup.measureChildCalledTime = 0;
1283         mMockViewGroup.measureChildren(widthMeasureSpec, heightMeasureSpec);
1284         assertEquals(1, mMockViewGroup.measureChildCalledTime);
1285 
1286         MockTextView textView2 = new MockTextView(mContext);
1287         textView2.setVisibility(View.GONE);
1288         mMockViewGroup.addView(textView2);
1289 
1290         mMockViewGroup.measureChildCalledTime = 0;
1291         mMockViewGroup.measureChildren(widthMeasureSpec, heightMeasureSpec);
1292         assertEquals(1, mMockViewGroup.measureChildCalledTime);
1293     }
1294 
1295     @UiThreadTest
1296     @Test
testMeasureChildWithMargins()1297     public void testMeasureChildWithMargins() {
1298         final int width = 10;
1299         final int height = 20;
1300         final int parentWidthMeasureSpec = 1;
1301         final int widthUsed = 2;
1302         final int parentHeightMeasureSpec = 3;
1303         final int heightUsed = 4;
1304         MockView child = new MockView(mContext);
1305 
1306         mMockViewGroup.addView(child);
1307         child.setLayoutParams(new ViewGroup.LayoutParams(width, height));
1308         try {
1309             mMockViewGroup.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
1310                     parentHeightMeasureSpec, heightUsed);
1311             fail("measureChildWithMargins should throw out class cast exception");
1312         } catch (RuntimeException e) {
1313         }
1314         child.setLayoutParams(new ViewGroup.MarginLayoutParams(width, height));
1315 
1316         mMockViewGroup.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
1317                 parentHeightMeasureSpec, heightUsed);
1318         assertEquals(ViewGroup.getChildMeasureSpec(parentWidthMeasureSpec, parentHeightMeasureSpec,
1319                 width), child.mWidthMeasureSpec);
1320         assertEquals(ViewGroup.getChildMeasureSpec(widthUsed, heightUsed, height),
1321                 child.mHeightMeasureSpec);
1322     }
1323 
1324     @UiThreadTest
1325     @Test
testOffsetDescendantRectToMyCoords()1326     public void testOffsetDescendantRectToMyCoords() {
1327         try {
1328             mMockViewGroup.offsetDescendantRectToMyCoords(mMockTextView, new Rect());
1329             fail("offsetDescendantRectToMyCoords should throw out "
1330                     + "IllegalArgumentException");
1331         } catch (RuntimeException e) {
1332             // expected
1333         }
1334         mMockViewGroup.addView(mMockTextView);
1335         mMockTextView.layout(1, 2, 3, 4);
1336         Rect rect = new Rect();
1337         mMockViewGroup.offsetDescendantRectToMyCoords(mMockTextView, rect);
1338         assertEquals(2, rect.bottom);
1339         assertEquals(2, rect.top);
1340         assertEquals(1, rect.left);
1341         assertEquals(1, rect.right);
1342     }
1343 
1344     @UiThreadTest
1345     @Test
testOffsetRectIntoDescendantCoords()1346     public void testOffsetRectIntoDescendantCoords() {
1347         mMockViewGroup.layout(10, 20, 30, 40);
1348 
1349         try {
1350             mMockViewGroup.offsetRectIntoDescendantCoords(mMockTextView, new Rect());
1351             fail("offsetRectIntoDescendantCoords should throw out "
1352                     + "IllegalArgumentException");
1353         } catch (RuntimeException e) {
1354             // expected
1355         }
1356         mMockTextView.layout(1, 2, 3, 4);
1357         mMockViewGroup.addView(mMockTextView);
1358 
1359         Rect rect = new Rect(5, 6, 7, 8);
1360         mMockViewGroup.offsetRectIntoDescendantCoords(mMockTextView, rect);
1361         assertEquals(6, rect.bottom);
1362         assertEquals(4, rect.top);
1363         assertEquals(4, rect.left);
1364         assertEquals(6, rect.right);
1365     }
1366 
1367     @UiThreadTest
1368     @Test
testOnAnimationEnd()1369     public void testOnAnimationEnd() {
1370         // this function is a call back function it should be tested in ViewGroup#drawChild.
1371         MockViewGroup parent = new MockViewGroup(mContext);
1372         MockViewGroup child = new MockViewGroup(mContext);
1373         child.setAnimation(new MockAnimation());
1374         // this call will make mPrivateFlags |= ANIMATION_STARTED;
1375         child.onAnimationStart();
1376         parent.addView(child);
1377 
1378         MockCanvas canvas = new MockCanvas();
1379         assertFalse(parent.drawChild(canvas, child, 100));
1380         assertTrue(child.isOnAnimationEndCalled);
1381     }
1382 
1383     private class MockAnimation extends Animation {
MockAnimation()1384         public MockAnimation() {
1385             super();
1386         }
1387 
MockAnimation(Context context, AttributeSet attrs)1388         public MockAnimation(Context context, AttributeSet attrs) {
1389             super(context, attrs);
1390         }
1391 
1392         @Override
getTransformation(long currentTime, Transformation outTransformation)1393         public boolean getTransformation(long currentTime, Transformation outTransformation) {
1394            super.getTransformation(currentTime, outTransformation);
1395            return false;
1396         }
1397     }
1398 
1399     @UiThreadTest
1400     @Test
testOnAnimationStart()1401     public void testOnAnimationStart() {
1402         // This is a call back method. It should be tested in ViewGroup#drawChild.
1403         MockViewGroup parent = new MockViewGroup(mContext);
1404         MockViewGroup child = new MockViewGroup(mContext);
1405 
1406         parent.addView(child);
1407 
1408         MockCanvas canvas = new MockCanvas();
1409         try {
1410             assertFalse(parent.drawChild(canvas, child, 100));
1411             assertFalse(child.isOnAnimationStartCalled);
1412         } catch (Exception e) {
1413             // expected
1414         }
1415 
1416         child.setAnimation(new MockAnimation());
1417         assertFalse(parent.drawChild(canvas, child, 100));
1418         assertTrue(child.isOnAnimationStartCalled);
1419     }
1420 
1421     @UiThreadTest
1422     @Test
testOnCreateDrawableState()1423     public void testOnCreateDrawableState() {
1424         // Call back function. Called in View#getDrawableState()
1425         int[] data = mMockViewGroup.getDrawableState();
1426         assertTrue(mMockViewGroup.isOnCreateDrawableStateCalled);
1427         assertEquals(1, data.length);
1428     }
1429 
1430     @UiThreadTest
1431     @Test
testOnInterceptTouchEvent()1432     public void testOnInterceptTouchEvent() {
1433         MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(),
1434                 SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 100, 100, 0);
1435 
1436         assertFalse(mMockViewGroup.dispatchTouchEvent(me));
1437         assertTrue(mMockViewGroup.isOnInterceptTouchEventCalled);
1438     }
1439 
1440     @UiThreadTest
1441     @Test
testOnLayout()1442     public void testOnLayout() {
1443         final int left = 1;
1444         final int top = 2;
1445         final int right = 100;
1446         final int bottom = 200;
1447         mMockViewGroup.layout(left, top, right, bottom);
1448         assertEquals(left, mMockViewGroup.left);
1449         assertEquals(top, mMockViewGroup.top);
1450         assertEquals(right, mMockViewGroup.right);
1451         assertEquals(bottom, mMockViewGroup.bottom);
1452     }
1453 
1454     @UiThreadTest
1455     @Test
testOnRequestFocusInDescendants()1456     public void testOnRequestFocusInDescendants() {
1457         mMockViewGroup.requestFocus(View.FOCUS_DOWN, new Rect());
1458         assertTrue(mMockViewGroup.isOnRequestFocusInDescendantsCalled);
1459     }
1460 
1461     @UiThreadTest
1462     @Test
testRemoveAllViews()1463     public void testRemoveAllViews() {
1464         assertEquals(0, mMockViewGroup.getChildCount());
1465 
1466         mMockViewGroup.addView(mMockTextView);
1467         assertEquals(1, mMockViewGroup.getChildCount());
1468 
1469         mMockViewGroup.removeAllViews();
1470         assertEquals(0, mMockViewGroup.getChildCount());
1471         assertNull(mMockTextView.getParent());
1472     }
1473 
1474     @UiThreadTest
1475     @Test
testRemoveAllViewsInLayout()1476     public void testRemoveAllViewsInLayout() {
1477         MockViewGroup parent = new MockViewGroup(mContext);
1478         MockViewGroup child = new MockViewGroup(mContext);
1479 
1480         assertEquals(0, parent.getChildCount());
1481 
1482         child.addView(mMockTextView);
1483         parent.addView(child);
1484         assertEquals(1, parent.getChildCount());
1485 
1486         parent.removeAllViewsInLayout();
1487         assertEquals(0, parent.getChildCount());
1488         assertEquals(1, child.getChildCount());
1489         assertNull(child.getParent());
1490         assertSame(child, mMockTextView.getParent());
1491     }
1492 
1493     @UiThreadTest
1494     @Test
testRemoveDetachedView()1495     public void testRemoveDetachedView() {
1496         MockViewGroup parent = new MockViewGroup(mContext);
1497         MockViewGroup child1 = new MockViewGroup(mContext);
1498         MockViewGroup child2 = new MockViewGroup(mContext);
1499         ViewGroup.OnHierarchyChangeListener listener =
1500                 mock(ViewGroup.OnHierarchyChangeListener.class);
1501         parent.setOnHierarchyChangeListener(listener);
1502         parent.addView(child1);
1503         parent.addView(child2);
1504 
1505         parent.removeDetachedView(child1, false);
1506 
1507         InOrder inOrder = inOrder(listener);
1508         inOrder.verify(listener, times(1)).onChildViewAdded(parent, child1);
1509         inOrder.verify(listener, times(1)).onChildViewAdded(parent, child2);
1510         inOrder.verify(listener, times(1)).onChildViewRemoved(parent, child1);
1511     }
1512 
1513     @UiThreadTest
1514     @Test
testRemoveView()1515     public void testRemoveView() {
1516         MockViewGroup parent = new MockViewGroup(mContext);
1517         MockViewGroup child = new MockViewGroup(mContext);
1518 
1519         assertEquals(0, parent.getChildCount());
1520 
1521         parent.addView(child);
1522         assertEquals(1, parent.getChildCount());
1523 
1524         parent.removeView(child);
1525         assertEquals(0, parent.getChildCount());
1526         assertNull(child.getParent());
1527         assertTrue(parent.isOnViewRemovedCalled);
1528     }
1529 
1530     @UiThreadTest
1531     @Test
testRemoveViewAt()1532     public void testRemoveViewAt() {
1533         MockViewGroup parent = new MockViewGroup(mContext);
1534         MockViewGroup child = new MockViewGroup(mContext);
1535 
1536         assertEquals(0, parent.getChildCount());
1537 
1538         parent.addView(child);
1539         assertEquals(1, parent.getChildCount());
1540 
1541         try {
1542             parent.removeViewAt(2);
1543             fail("should throw out null pointer exception");
1544         } catch (RuntimeException e) {
1545             // expected
1546         }
1547         assertEquals(1, parent.getChildCount());
1548 
1549         parent.removeViewAt(0);
1550         assertEquals(0, parent.getChildCount());
1551         assertNull(child.getParent());
1552         assertTrue(parent.isOnViewRemovedCalled);
1553     }
1554 
1555     @UiThreadTest
1556     @Test
testRemoveViewInLayout()1557     public void testRemoveViewInLayout() {
1558         MockViewGroup parent = new MockViewGroup(mContext);
1559         MockViewGroup child = new MockViewGroup(mContext);
1560 
1561         assertEquals(0, parent.getChildCount());
1562 
1563         parent.addView(child);
1564         assertEquals(1, parent.getChildCount());
1565 
1566         parent.removeViewInLayout(child);
1567         assertEquals(0, parent.getChildCount());
1568         assertNull(child.getParent());
1569         assertTrue(parent.isOnViewRemovedCalled);
1570     }
1571 
1572     @UiThreadTest
1573     @Test
testRemoveViews()1574     public void testRemoveViews() {
1575         MockViewGroup parent = new MockViewGroup(mContext);
1576         MockViewGroup child1 = new MockViewGroup(mContext);
1577         MockViewGroup child2 = new MockViewGroup(mContext);
1578 
1579         assertEquals(0, parent.getChildCount());
1580         parent.addView(child1);
1581         parent.addView(child2);
1582         assertEquals(2, parent.getChildCount());
1583 
1584         try {
1585             parent.removeViews(-1, 1); // negative begin
1586             fail("should fail with IndexOutOfBoundsException");
1587         } catch (IndexOutOfBoundsException e) {}
1588 
1589         try {
1590             parent.removeViews(0, -1); // negative count
1591             fail("should fail with IndexOutOfBoundsException");
1592         } catch (IndexOutOfBoundsException e) {}
1593 
1594         try {
1595             parent.removeViews(1, 2); // past end
1596             fail("should fail with IndexOutOfBoundsException");
1597         } catch (IndexOutOfBoundsException e) {}
1598         assertEquals(2, parent.getChildCount()); // child list unmodified
1599 
1600         parent.removeViews(0, 1);
1601         assertEquals(1, parent.getChildCount());
1602         assertNull(child1.getParent());
1603 
1604         parent.removeViews(0, 1);
1605         assertEquals(0, parent.getChildCount());
1606         assertNull(child2.getParent());
1607         assertTrue(parent.isOnViewRemovedCalled);
1608     }
1609 
1610     @UiThreadTest
1611     @Test
testRemoveViewsInLayout()1612     public void testRemoveViewsInLayout() {
1613         MockViewGroup parent = new MockViewGroup(mContext);
1614         MockViewGroup child1 = new MockViewGroup(mContext);
1615         MockViewGroup child2 = new MockViewGroup(mContext);
1616 
1617         assertEquals(0, parent.getChildCount());
1618         parent.addView(child1);
1619         parent.addView(child2);
1620         assertEquals(2, parent.getChildCount());
1621 
1622         try {
1623             parent.removeViewsInLayout(-1, 1); // negative begin
1624             fail("should fail with IndexOutOfBoundsException");
1625         } catch (IndexOutOfBoundsException e) {}
1626 
1627         try {
1628             parent.removeViewsInLayout(0, -1); // negative count
1629             fail("should fail with IndexOutOfBoundsException");
1630         } catch (IndexOutOfBoundsException e) {}
1631 
1632         try {
1633             parent.removeViewsInLayout(1, 2); // past end
1634             fail("should fail with IndexOutOfBoundsException");
1635         } catch (IndexOutOfBoundsException e) {}
1636         assertEquals(2, parent.getChildCount()); // child list unmodified
1637 
1638         parent.removeViewsInLayout(0, 1);
1639         assertEquals(1, parent.getChildCount());
1640         assertNull(child1.getParent());
1641 
1642         parent.removeViewsInLayout(0, 1);
1643         assertEquals(0, parent.getChildCount());
1644         assertNull(child2.getParent());
1645         assertTrue(parent.isOnViewRemovedCalled);
1646     }
1647 
1648     @UiThreadTest
1649     @Test
testRequestChildFocus()1650     public void testRequestChildFocus() {
1651         mMockViewGroup.addView(mTextView);
1652         mMockViewGroup.requestChildFocus(mTextView, null);
1653 
1654         assertNotNull(mMockViewGroup.getFocusedChild());
1655 
1656         mMockViewGroup.clearChildFocus(mTextView);
1657         assertNull(mMockViewGroup.getFocusedChild());
1658     }
1659 
1660     @UiThreadTest
1661     @Test
testRequestChildRectangleOnScreen()1662     public void testRequestChildRectangleOnScreen() {
1663         assertFalse(mMockViewGroup.requestChildRectangleOnScreen(null, null, false));
1664     }
1665 
1666     @UiThreadTest
1667     @Test
testRequestDisallowInterceptTouchEvent()1668     public void testRequestDisallowInterceptTouchEvent() {
1669         MockView child = new MockView(mContext);
1670 
1671         mMockViewGroup.addView(child);
1672         child.requestDisallowInterceptTouchEvent(true);
1673         child.requestDisallowInterceptTouchEvent(false);
1674         assertTrue(mMockViewGroup.isRequestDisallowInterceptTouchEventCalled);
1675     }
1676 
1677     @UiThreadTest
1678     @Test
testRequestFocus()1679     public void testRequestFocus() {
1680         mMockViewGroup.requestFocus(View.FOCUS_DOWN, new Rect());
1681         assertTrue(mMockViewGroup.isOnRequestFocusInDescendantsCalled);
1682     }
1683 
1684     private class TestClusterHier {
1685         public MockViewGroup top = new MockViewGroup(mContext);
1686         public MockViewGroup cluster1 = new MockViewGroup(mContext);
1687         public Button c1view1 = new Button(mContext);
1688         public Button c1view2 = new Button(mContext);
1689         public MockViewGroup cluster2 = new MockViewGroup(mContext);
1690         public MockViewGroup nestedGroup = new MockViewGroup(mContext);
1691         public Button c2view1 = new Button(mContext);
1692         public Button c2view2 = new Button(mContext);
TestClusterHier()1693         TestClusterHier() {
1694             this(true);
1695         }
TestClusterHier(boolean inTouchMode)1696         TestClusterHier(boolean inTouchMode) {
1697             for (Button bt : new Button[]{c1view1, c1view2, c2view1, c2view2}) {
1698                 // Otherwise this test won't work during suite-run.
1699                 bt.setFocusableInTouchMode(inTouchMode);
1700             }
1701             for (MockViewGroup mvg : new MockViewGroup[]{top, cluster1, cluster2, nestedGroup}) {
1702                 mvg.returnActualFocusSearchResult = true;
1703             }
1704             top.setIsRootNamespace(true);
1705             cluster1.setKeyboardNavigationCluster(true);
1706             cluster2.setKeyboardNavigationCluster(true);
1707             cluster1.addView(c1view1);
1708             cluster1.addView(c1view2);
1709             cluster2.addView(c2view1);
1710             nestedGroup.addView(c2view2);
1711             cluster2.addView(nestedGroup);
1712             top.addView(cluster1);
1713             top.addView(cluster2);
1714         }
1715     }
1716 
1717     @UiThreadTest
1718     @Test
testRestoreFocusInCluster()1719     public void testRestoreFocusInCluster() {
1720         TestClusterHier h = new TestClusterHier();
1721         h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN);
1722         assertSame(h.c1view1, h.top.findFocus());
1723 
1724         h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN);
1725         assertSame(h.c2view1, h.top.findFocus());
1726 
1727         h.c2view2.setFocusedInCluster();
1728         h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN);
1729         assertSame(h.c2view2, h.top.findFocus());
1730         h.c2view1.setFocusedInCluster();
1731         h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN);
1732         assertSame(h.c2view1, h.top.findFocus());
1733 
1734         h.c1view2.setFocusedInCluster();
1735         h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN);
1736         assertSame(h.c1view2, h.top.findFocus());
1737 
1738         h = new TestClusterHier();
1739         h.cluster1.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
1740         h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN);
1741         assertNull(h.top.findFocus());
1742 
1743         h.c2view1.setVisibility(View.INVISIBLE);
1744         h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN);
1745         assertSame(h.c2view2, h.top.findFocus());
1746 
1747         // Nested clusters should be ignored.
1748         h = new TestClusterHier();
1749         h.c1view1.setFocusedInCluster();
1750         h.nestedGroup.setKeyboardNavigationCluster(true);
1751         h.c2view2.setFocusedInCluster();
1752         h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN);
1753         assertSame(h.c2view2, h.top.findFocus());
1754     }
1755 
1756     @UiThreadTest
1757     @Test
testDefaultCluster()1758     public void testDefaultCluster() {
1759         TestClusterHier h = new TestClusterHier();
1760         h.cluster2.setKeyboardNavigationCluster(false);
1761         assertTrue(h.top.restoreFocusNotInCluster());
1762         assertSame(h.c2view1, h.top.findFocus());
1763 
1764         // Check saves state within non-cluster
1765         h = new TestClusterHier();
1766         h.cluster2.setKeyboardNavigationCluster(false);
1767         h.c2view2.setFocusedInCluster();
1768         assertTrue(h.top.restoreFocusNotInCluster());
1769         assertSame(h.c2view2, h.top.findFocus());
1770 
1771         // Check that focusable view groups have descendantFocusability honored.
1772         h = new TestClusterHier();
1773         h.cluster2.setKeyboardNavigationCluster(false);
1774         h.cluster2.setFocusableInTouchMode(true);
1775         h.cluster2.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
1776         assertTrue(h.top.restoreFocusNotInCluster());
1777         assertSame(h.c2view1, h.top.findFocus());
1778         h = new TestClusterHier();
1779         h.cluster2.setKeyboardNavigationCluster(false);
1780         h.cluster2.setFocusableInTouchMode(true);
1781         h.cluster2.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
1782         assertTrue(h.top.restoreFocusNotInCluster());
1783         assertSame(h.cluster2, h.top.findFocus());
1784 
1785         // Check that we return false if nothing out-of-cluster is focusable
1786         // (also tests FOCUS_BLOCK_DESCENDANTS)
1787         h = new TestClusterHier();
1788         h.cluster2.setKeyboardNavigationCluster(false);
1789         h.cluster2.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
1790         assertFalse(h.top.restoreFocusNotInCluster());
1791         assertNull(h.top.findFocus());
1792     }
1793 
1794     @UiThreadTest
1795     @Test
testFocusInClusterRemovals()1796     public void testFocusInClusterRemovals() {
1797         // Removing focused-in-cluster view from its parent in various ways.
1798         TestClusterHier h = new TestClusterHier();
1799         h.c1view1.setFocusedInCluster();
1800         h.cluster1.removeView(h.c1view1);
1801         h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN);
1802         assertSame(h.c1view2, h.cluster1.findFocus());
1803 
1804         h = new TestClusterHier();
1805         h.c1view1.setFocusedInCluster();
1806         h.cluster1.removeViews(0, 1);
1807         h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN);
1808         assertSame(h.c1view2, h.cluster1.findFocus());
1809 
1810         h = new TestClusterHier();
1811         h.c2view1.setFocusedInCluster();
1812         h.cluster2.removeAllViewsInLayout();
1813         h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN);
1814         assertNull(h.cluster2.findFocus());
1815 
1816         h = new TestClusterHier();
1817         h.c1view1.setFocusedInCluster();
1818         h.cluster1.detachViewFromParent(h.c1view1);
1819         h.cluster1.attachViewToParent(h.c1view1, 1, null);
1820         h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN);
1821         assertSame(h.c1view1, h.cluster1.findFocus());
1822 
1823         h = new TestClusterHier();
1824         h.c1view1.setFocusedInCluster();
1825         h.cluster1.detachViewFromParent(h.c1view1);
1826         h.cluster1.removeDetachedView(h.c1view1, false);
1827         h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN);
1828         assertSame(h.c1view2, h.cluster1.findFocus());
1829     }
1830 
1831     @UiThreadTest
1832     @Test
testFocusInClusterFocusableChanges()1833     public void testFocusInClusterFocusableChanges() {
1834         TestClusterHier h = new TestClusterHier();
1835         h.cluster1.setKeyboardNavigationCluster(false);
1836         h.c1view2.setFocusedInCluster();
1837         h.c2view1.requestFocus();
1838         assertSame(h.top.findFocus(), h.c2view1);
1839         assertTrue(h.top.restoreFocusNotInCluster());
1840         assertSame(h.top.findFocus(), h.c1view2);
1841         h.c1view1.setFocusable(false);
1842         // making it invisible should clear focusNotInCluster chain
1843         h.c1view2.setVisibility(View.INVISIBLE);
1844         assertFalse(h.top.restoreFocusNotInCluster());
1845         h.c1view2.setVisibility(View.VISIBLE);
1846         h.c1view2.requestFocus();
1847         h.c1view2.setFocusedInCluster();
1848         h.c2view1.setFocusable(false);
1849         h.c2view2.setFocusable(false);
1850         assertFalse(h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN));
1851     }
1852 
1853     @UiThreadTest
1854     @Test
testRestoreDefaultFocus()1855     public void testRestoreDefaultFocus() {
1856         TestClusterHier h = new TestClusterHier();
1857         h.c1view2.setFocusedByDefault(true);
1858         h.top.restoreDefaultFocus();
1859         assertSame(h.c1view2, h.top.findFocus());
1860 
1861         h.c1view2.setFocusedByDefault(false);
1862         h.top.restoreDefaultFocus();
1863         assertSame(h.c1view1, h.top.findFocus());
1864 
1865         // default focus favors higher-up views
1866         h.c1view2.setFocusedByDefault(true);
1867         h.cluster1.setFocusedByDefault(true);
1868         h.top.restoreDefaultFocus();
1869         assertSame(h.c1view2, h.top.findFocus());
1870         h.c2view1.setFocusedByDefault(true);
1871         h.top.restoreDefaultFocus();
1872         assertSame(h.c1view2, h.top.findFocus());
1873         h.cluster2.setFocusedByDefault(true);
1874         h.cluster1.setFocusedByDefault(false);
1875         h.top.restoreDefaultFocus();
1876         assertSame(h.c2view1, h.top.findFocus());
1877 
1878         // removing default receivers should resolve to an existing default
1879         h = new TestClusterHier();
1880         h.c1view2.setFocusedByDefault(true);
1881         h.cluster1.setFocusedByDefault(true);
1882         h.c2view2.setFocusedByDefault(true);
1883         h.top.restoreDefaultFocus();
1884         assertSame(h.c1view2, h.top.findFocus());
1885         h.c1view2.setFocusedByDefault(false);
1886         h.cluster1.setFocusedByDefault(false);
1887         // only 1 focused-by-default view left, but its in a different branch. Should still pull
1888         // default focus.
1889         h.top.restoreDefaultFocus();
1890         assertSame(h.c2view2, h.top.findFocus());
1891     }
1892 
1893     @UiThreadTest
1894     @Test
testDefaultFocusViewRemoved()1895     public void testDefaultFocusViewRemoved() {
1896         // Removing default-focus view from its parent in various ways.
1897         TestClusterHier h = new TestClusterHier();
1898         h.c1view1.setFocusedByDefault(true);
1899         h.cluster1.removeView(h.c1view1);
1900         h.cluster1.restoreDefaultFocus();
1901         assertSame(h.c1view2, h.cluster1.findFocus());
1902 
1903         h = new TestClusterHier();
1904         h.c1view1.setFocusedByDefault(true);
1905         h.cluster1.removeViews(0, 1);
1906         h.cluster1.restoreDefaultFocus();
1907         assertSame(h.c1view2, h.cluster1.findFocus());
1908 
1909         h = new TestClusterHier();
1910         h.c1view1.setFocusedByDefault(true);
1911         h.cluster1.removeAllViewsInLayout();
1912         h.cluster1.restoreDefaultFocus();
1913         assertNull(h.cluster1.findFocus());
1914 
1915         h = new TestClusterHier();
1916         h.c1view1.setFocusedByDefault(true);
1917         h.cluster1.detachViewFromParent(h.c1view1);
1918         h.cluster1.attachViewToParent(h.c1view1, 1, null);
1919         h.cluster1.restoreDefaultFocus();
1920         assertSame(h.c1view1, h.cluster1.findFocus());
1921 
1922         h = new TestClusterHier();
1923         h.c1view1.setFocusedByDefault(true);
1924         h.cluster1.detachViewFromParent(h.c1view1);
1925         h.cluster1.removeDetachedView(h.c1view1, false);
1926         h.cluster1.restoreDefaultFocus();
1927         assertSame(h.c1view2, h.cluster1.findFocus());
1928     }
1929 
1930     @UiThreadTest
1931     @Test
testAddViewWithDefaultFocus()1932     public void testAddViewWithDefaultFocus() {
1933         // Adding a view that has default focus propagates the default focus chain to the root.
1934         mMockViewGroup = new MockViewGroup(mContext);
1935         mMockTextView = new MockTextView(mContext);
1936         mMockTextView.setFocusable(true);
1937         mTextView = new TextView(mContext);
1938         mTextView.setFocusable(true);
1939         mTextView.setFocusableInTouchMode(true);
1940         mTextView.setFocusedByDefault(true);
1941         mMockViewGroup.addView(mMockTextView);
1942         mMockViewGroup.addView(mTextView);
1943         mMockViewGroup.restoreDefaultFocus();
1944         assertTrue(mTextView.isFocused());
1945     }
1946 
1947     @UiThreadTest
1948     @Test
testDefaultFocusWorksForClusters()1949     public void testDefaultFocusWorksForClusters() {
1950         TestClusterHier h = new TestClusterHier();
1951         h.c2view2.setFocusedByDefault(true);
1952         h.cluster1.setFocusedByDefault(true);
1953         h.top.restoreDefaultFocus();
1954         assertSame(h.c1view1, h.top.findFocus());
1955         h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN);
1956         assertSame(h.c2view2, h.top.findFocus());
1957 
1958         // make sure focused in cluster takes priority in cluster-focus
1959         h.c1view2.setFocusedByDefault(true);
1960         h.c1view1.setFocusedInCluster();
1961         h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN);
1962         assertSame(h.c1view1, h.top.findFocus());
1963     }
1964 
1965     @UiThreadTest
1966     @Test
testTouchscreenBlocksFocus()1967     public void testTouchscreenBlocksFocus() {
1968         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) {
1969             return;
1970         }
1971         InstrumentationRegistry.getInstrumentation().setInTouchMode(false);
1972 
1973         // Can't focus/default-focus an element in touchscreenBlocksFocus
1974         TestClusterHier h = new TestClusterHier(false);
1975         h.cluster1.setTouchscreenBlocksFocus(true);
1976         h.c1view2.setFocusedByDefault(true);
1977         h.top.restoreDefaultFocus();
1978         assertSame(h.c2view1, h.top.findFocus());
1979         ArrayList<View> views = new ArrayList<>();
1980         h.top.addFocusables(views, View.FOCUS_DOWN);
1981         for (View v : views) {
1982             assertFalse(v.getParent() == h.cluster1);
1983         }
1984         views.clear();
1985 
1986         // Can cluster navigate into it though
1987         h.top.addKeyboardNavigationClusters(views, View.FOCUS_DOWN);
1988         assertTrue(views.contains(h.cluster1));
1989         views.clear();
1990         h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN);
1991         assertSame(h.c1view2, h.top.findFocus());
1992         // can normal-navigate around once inside
1993         h.top.addFocusables(views, View.FOCUS_DOWN);
1994         assertTrue(views.contains(h.c1view1));
1995         views.clear();
1996         h.c1view1.requestFocus();
1997         assertSame(h.c1view1, h.top.findFocus());
1998         // focus loops within cluster (doesn't leave)
1999         h.c1view2.requestFocus();
2000         View next = h.top.focusSearch(h.c1view2, View.FOCUS_FORWARD);
2001         assertSame(h.c1view1, next);
2002         // but once outside, can no-longer navigate in.
2003         h.c2view2.requestFocus();
2004         h.c1view1.requestFocus();
2005         assertSame(h.c2view2, h.top.findFocus());
2006 
2007         h = new TestClusterHier(false);
2008         h.c1view1.requestFocus();
2009         h.nestedGroup.setKeyboardNavigationCluster(true);
2010         h.nestedGroup.setTouchscreenBlocksFocus(true);
2011         // since cluster is nested, it should ignore its touchscreenBlocksFocus behavior.
2012         h.c2view2.requestFocus();
2013         assertSame(h.c2view2, h.top.findFocus());
2014         h.top.addFocusables(views, View.FOCUS_DOWN);
2015         assertTrue(views.contains(h.c2view2));
2016         views.clear();
2017     }
2018 
2019     @UiThreadTest
2020     @Test
testRequestTransparentRegion()2021     public void testRequestTransparentRegion() {
2022         MockViewGroup parent = new MockViewGroup(mContext);
2023         MockView child1 = new MockView(mContext);
2024         MockView child2 = new MockView(mContext);
2025         child1.addView(child2);
2026         parent.addView(child1);
2027         child1.requestTransparentRegion(child2);
2028         assertTrue(parent.isRequestTransparentRegionCalled);
2029     }
2030 
2031     @UiThreadTest
2032     @Test
testScheduleLayoutAnimation()2033     public void testScheduleLayoutAnimation() {
2034         Animation animation = new AlphaAnimation(mContext, null);
2035 
2036         LayoutAnimationController al = spy(new LayoutAnimationController(animation));
2037         mMockViewGroup.setLayoutAnimation(al);
2038         mMockViewGroup.scheduleLayoutAnimation();
2039         mMockViewGroup.dispatchDraw(new Canvas());
2040         verify(al, times(1)).start();
2041     }
2042 
2043     @UiThreadTest
2044     @Test
testSetAddStatesFromChildren()2045     public void testSetAddStatesFromChildren() {
2046         mMockViewGroup.setAddStatesFromChildren(true);
2047         assertTrue(mMockViewGroup.addStatesFromChildren());
2048 
2049         mMockViewGroup.setAddStatesFromChildren(false);
2050         assertFalse(mMockViewGroup.addStatesFromChildren());
2051     }
2052 
2053     @UiThreadTest
2054     @Test
testSetChildrenDrawingCacheEnabled()2055     public void testSetChildrenDrawingCacheEnabled() {
2056         assertTrue(mMockViewGroup.isAnimationCacheEnabled());
2057 
2058         mMockViewGroup.setAnimationCacheEnabled(false);
2059         assertFalse(mMockViewGroup.isAnimationCacheEnabled());
2060 
2061         mMockViewGroup.setAnimationCacheEnabled(true);
2062         assertTrue(mMockViewGroup.isAnimationCacheEnabled());
2063     }
2064 
2065     @UiThreadTest
2066     @Test
testSetChildrenDrawnWithCacheEnabled()2067     public void testSetChildrenDrawnWithCacheEnabled() {
2068         assertFalse(mMockViewGroup.isChildrenDrawnWithCacheEnabled());
2069 
2070         mMockViewGroup.setChildrenDrawnWithCacheEnabled(true);
2071         assertTrue(mMockViewGroup.isChildrenDrawnWithCacheEnabled());
2072 
2073         mMockViewGroup.setChildrenDrawnWithCacheEnabled(false);
2074         assertFalse(mMockViewGroup.isChildrenDrawnWithCacheEnabled());
2075     }
2076 
2077     @UiThreadTest
2078     @Test
testSetClipChildren()2079     public void testSetClipChildren() {
2080         Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
2081 
2082         mMockTextView.layout(1, 2, 30, 40);
2083         mMockViewGroup.layout(1, 1, 100, 200);
2084         mMockViewGroup.setClipChildren(true);
2085 
2086         MockCanvas canvas = new MockCanvas(bitmap);
2087         mMockViewGroup.drawChild(canvas, mMockTextView, 100);
2088         Rect rect = canvas.getClipBounds();
2089         assertEquals(0, rect.top);
2090         assertEquals(100, rect.bottom);
2091         assertEquals(0, rect.left);
2092         assertEquals(100, rect.right);
2093     }
2094 
2095     class MockCanvas extends Canvas {
2096 
2097         public int mLeft;
2098         public int mTop;
2099         public int mRight;
2100         public int mBottom;
2101 
MockCanvas()2102         public MockCanvas() {
2103             super(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888));
2104         }
2105 
MockCanvas(Bitmap bitmap)2106         public MockCanvas(Bitmap bitmap) {
2107             super(bitmap);
2108         }
2109 
2110         @Override
quickReject(float left, float top, float right, float bottom, EdgeType type)2111         public boolean quickReject(float left, float top, float right,
2112                 float bottom, EdgeType type) {
2113             super.quickReject(left, top, right, bottom, type);
2114             return false;
2115         }
2116 
2117         @Override
clipRect(int left, int top, int right, int bottom)2118         public boolean clipRect(int left, int top, int right, int bottom) {
2119             mLeft = left;
2120             mTop = top;
2121             mRight = right;
2122             mBottom = bottom;
2123             return super.clipRect(left, top, right, bottom);
2124         }
2125     }
2126 
2127     @UiThreadTest
2128     @Test
testSetClipToPadding()2129     public void testSetClipToPadding() {
2130         final int frameLeft = 1;
2131         final int frameTop = 2;
2132         final int frameRight = 100;
2133         final int frameBottom = 200;
2134         mMockViewGroup.layout(frameLeft, frameTop, frameRight, frameBottom);
2135 
2136         mMockViewGroup.setClipToPadding(true);
2137         MockCanvas canvas = new MockCanvas();
2138         final int paddingLeft = 10;
2139         final int paddingTop = 20;
2140         final int paddingRight = 100;
2141         final int paddingBottom = 200;
2142         mMockViewGroup.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
2143         mMockViewGroup.dispatchDraw(canvas);
2144         //check that the clip region does not contain the padding area
2145         assertEquals(10, canvas.mLeft);
2146         assertEquals(20, canvas.mTop);
2147         assertEquals(-frameLeft, canvas.mRight);
2148         assertEquals(-frameTop, canvas.mBottom);
2149 
2150         mMockViewGroup.setClipToPadding(false);
2151         canvas = new MockCanvas();
2152         mMockViewGroup.dispatchDraw(canvas);
2153         assertEquals(0, canvas.mLeft);
2154         assertEquals(0, canvas.mTop);
2155         assertEquals(0, canvas.mRight);
2156         assertEquals(0, canvas.mBottom);
2157     }
2158 
2159     @UiThreadTest
2160     @Test
testSetDescendantFocusability()2161     public void testSetDescendantFocusability() {
2162         final int FLAG_MASK_FOCUSABILITY = 0x60000;
2163         assertFalse((mMockViewGroup.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0);
2164 
2165         mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
2166         assertFalse((mMockViewGroup.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0);
2167 
2168         mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
2169         assertFalse((mMockViewGroup.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0);
2170         assertFalse((mMockViewGroup.getDescendantFocusability() &
2171                 ViewGroup.FOCUS_BEFORE_DESCENDANTS) == 0);
2172     }
2173 
2174     @UiThreadTest
2175     @Test
testSetOnHierarchyChangeListener()2176     public void testSetOnHierarchyChangeListener() {
2177         MockViewGroup parent = new MockViewGroup(mContext);
2178         MockViewGroup child = new MockViewGroup(mContext);
2179         ViewGroup.OnHierarchyChangeListener listener =
2180                 mock(ViewGroup.OnHierarchyChangeListener.class);
2181         parent.setOnHierarchyChangeListener(listener);
2182         parent.addView(child);
2183 
2184         parent.removeDetachedView(child, false);
2185         InOrder inOrder = inOrder(listener);
2186         inOrder.verify(listener, times(1)).onChildViewAdded(parent, child);
2187         inOrder.verify(listener, times(1)).onChildViewRemoved(parent, child);
2188     }
2189 
2190     @UiThreadTest
2191     @Test
testSetPadding()2192     public void testSetPadding() {
2193         final int left = 1;
2194         final int top = 2;
2195         final int right = 3;
2196         final int bottom = 4;
2197 
2198         assertEquals(0, mMockViewGroup.getPaddingBottom());
2199         assertEquals(0, mMockViewGroup.getPaddingTop());
2200         assertEquals(0, mMockViewGroup.getPaddingLeft());
2201         assertEquals(0, mMockViewGroup.getPaddingRight());
2202         assertEquals(0, mMockViewGroup.getPaddingStart());
2203         assertEquals(0, mMockViewGroup.getPaddingEnd());
2204 
2205         mMockViewGroup.setPadding(left, top, right, bottom);
2206 
2207         assertEquals(bottom, mMockViewGroup.getPaddingBottom());
2208         assertEquals(top, mMockViewGroup.getPaddingTop());
2209         assertEquals(left, mMockViewGroup.getPaddingLeft());
2210         assertEquals(right, mMockViewGroup.getPaddingRight());
2211 
2212         assertEquals(left, mMockViewGroup.getPaddingStart());
2213         assertEquals(right, mMockViewGroup.getPaddingEnd());
2214         assertEquals(false, mMockViewGroup.isPaddingRelative());
2215 
2216         // force RTL direction
2217         mMockViewGroup.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
2218 
2219         assertEquals(bottom, mMockViewGroup.getPaddingBottom());
2220         assertEquals(top, mMockViewGroup.getPaddingTop());
2221         assertEquals(left, mMockViewGroup.getPaddingLeft());
2222         assertEquals(right, mMockViewGroup.getPaddingRight());
2223 
2224         assertEquals(right, mMockViewGroup.getPaddingStart());
2225         assertEquals(left, mMockViewGroup.getPaddingEnd());
2226         assertEquals(false, mMockViewGroup.isPaddingRelative());
2227     }
2228 
2229     @UiThreadTest
2230     @Test
testSetPaddingRelative()2231     public void testSetPaddingRelative() {
2232         final int start = 1;
2233         final int top = 2;
2234         final int end = 3;
2235         final int bottom = 4;
2236 
2237         assertEquals(0, mMockViewGroup.getPaddingBottom());
2238         assertEquals(0, mMockViewGroup.getPaddingTop());
2239         assertEquals(0, mMockViewGroup.getPaddingLeft());
2240         assertEquals(0, mMockViewGroup.getPaddingRight());
2241         assertEquals(0, mMockViewGroup.getPaddingStart());
2242         assertEquals(0, mMockViewGroup.getPaddingEnd());
2243 
2244         mMockViewGroup.setPaddingRelative(start, top, end, bottom);
2245 
2246         assertEquals(bottom, mMockViewGroup.getPaddingBottom());
2247         assertEquals(top, mMockViewGroup.getPaddingTop());
2248         assertEquals(start, mMockViewGroup.getPaddingLeft());
2249         assertEquals(end, mMockViewGroup.getPaddingRight());
2250 
2251         assertEquals(start, mMockViewGroup.getPaddingStart());
2252         assertEquals(end, mMockViewGroup.getPaddingEnd());
2253         assertEquals(true, mMockViewGroup.isPaddingRelative());
2254 
2255         // force RTL direction after setting relative padding
2256         mMockViewGroup.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
2257 
2258         assertEquals(bottom, mMockViewGroup.getPaddingBottom());
2259         assertEquals(top, mMockViewGroup.getPaddingTop());
2260         assertEquals(end, mMockViewGroup.getPaddingLeft());
2261         assertEquals(start, mMockViewGroup.getPaddingRight());
2262 
2263         assertEquals(start, mMockViewGroup.getPaddingStart());
2264         assertEquals(end, mMockViewGroup.getPaddingEnd());
2265         assertEquals(true, mMockViewGroup.isPaddingRelative());
2266 
2267         // force RTL direction before setting relative padding
2268         mMockViewGroup = new MockViewGroup(mContext);
2269         mMockViewGroup.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
2270 
2271         assertEquals(0, mMockViewGroup.getPaddingBottom());
2272         assertEquals(0, mMockViewGroup.getPaddingTop());
2273         assertEquals(0, mMockViewGroup.getPaddingLeft());
2274         assertEquals(0, mMockViewGroup.getPaddingRight());
2275         assertEquals(0, mMockViewGroup.getPaddingStart());
2276         assertEquals(0, mMockViewGroup.getPaddingEnd());
2277 
2278         mMockViewGroup.setPaddingRelative(start, top, end, bottom);
2279 
2280         assertEquals(bottom, mMockViewGroup.getPaddingBottom());
2281         assertEquals(top, mMockViewGroup.getPaddingTop());
2282         assertEquals(end, mMockViewGroup.getPaddingLeft());
2283         assertEquals(start, mMockViewGroup.getPaddingRight());
2284 
2285         assertEquals(start, mMockViewGroup.getPaddingStart());
2286         assertEquals(end, mMockViewGroup.getPaddingEnd());
2287         assertEquals(true, mMockViewGroup.isPaddingRelative());
2288     }
2289 
2290     @UiThreadTest
2291     @Test
testSetPersistentDrawingCache()2292     public void testSetPersistentDrawingCache() {
2293         mMockViewGroup.setPersistentDrawingCache(1);
2294         assertEquals(1 & ViewGroup.PERSISTENT_ALL_CACHES, mMockViewGroup
2295                 .getPersistentDrawingCache());
2296     }
2297 
2298     @UiThreadTest
2299     @Test
testShowContextMenuForChild()2300     public void testShowContextMenuForChild() {
2301         MockViewGroup parent = new MockViewGroup(mContext);
2302         MockViewGroup child = new MockViewGroup(mContext);
2303         parent.addView(child);
2304 
2305         child.showContextMenuForChild(null);
2306         assertTrue(parent.isShowContextMenuForChildCalled);
2307     }
2308 
2309     @UiThreadTest
2310     @Test
testShowContextMenuForChild_WithXYCoords()2311     public void testShowContextMenuForChild_WithXYCoords() {
2312         MockViewGroup parent = new MockViewGroup(mContext);
2313         MockViewGroup child = new MockViewGroup(mContext);
2314         parent.addView(child);
2315 
2316         child.showContextMenuForChild(null, 48, 48);
2317         assertTrue(parent.isShowContextMenuForChildCalledWithXYCoords);
2318     }
2319 
2320     @UiThreadTest
2321     @Test
testStartLayoutAnimation()2322     public void testStartLayoutAnimation() {
2323         RotateAnimation animation = new RotateAnimation(0.1f, 0.1f);
2324         LayoutAnimationController la = new LayoutAnimationController(animation);
2325         mMockViewGroup.setLayoutAnimation(la);
2326 
2327         mMockViewGroup.layout(1, 1, 100, 100);
2328         assertFalse(mMockViewGroup.isLayoutRequested());
2329         mMockViewGroup.startLayoutAnimation();
2330         assertTrue(mMockViewGroup.isLayoutRequested());
2331     }
2332 
2333     @UiThreadTest
2334     @Test
testUpdateViewLayout()2335     public void testUpdateViewLayout() {
2336         MockViewGroup parent = new MockViewGroup(mContext);
2337         MockViewGroup child = new MockViewGroup(mContext);
2338 
2339         parent.addView(child);
2340         LayoutParams param = new LayoutParams(100, 200);
2341         parent.updateViewLayout(child, param);
2342         assertEquals(param.width, child.getLayoutParams().width);
2343         assertEquals(param.height, child.getLayoutParams().height);
2344     }
2345 
2346     @UiThreadTest
2347     @Test
testDebug()2348     public void testDebug() {
2349         final int EXPECTED = 100;
2350         MockViewGroup parent = new MockViewGroup(mContext);
2351         MockViewGroup child = new MockViewGroup(mContext);
2352         parent.addView(child);
2353 
2354         parent.debug(EXPECTED);
2355         assertEquals(EXPECTED + 1, child.debugDepth);
2356     }
2357 
2358     @UiThreadTest
2359     @Test
testDispatchKeyEventPreIme()2360     public void testDispatchKeyEventPreIme() {
2361         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
2362         assertFalse(mMockViewGroup.dispatchKeyEventPreIme(event));
2363         assertFalse(mMockViewGroup.dispatchKeyShortcutEvent(event));
2364 
2365         mMockViewGroup.addView(mMockTextView);
2366         mMockViewGroup.requestChildFocus(mMockTextView, null);
2367         mMockViewGroup.layout(0, 0, 100, 200);
2368         assertFalse(mMockViewGroup.dispatchKeyEventPreIme(event));
2369         assertFalse(mMockViewGroup.dispatchKeyShortcutEvent(event));
2370 
2371         mMockViewGroup.requestChildFocus(mMockTextView, null);
2372         mMockTextView.layout(0, 0, 50, 50);
2373         assertTrue(mMockViewGroup.dispatchKeyEventPreIme(event));
2374         assertTrue(mMockViewGroup.dispatchKeyShortcutEvent(event));
2375 
2376         mMockViewGroup.setStaticTransformationsEnabled(true);
2377         Canvas canvas = new Canvas();
2378         mMockViewGroup.drawChild(canvas, mMockTextView, 100);
2379         assertTrue(mMockViewGroup.isGetChildStaticTransformationCalled);
2380         mMockViewGroup.isGetChildStaticTransformationCalled = false;
2381         mMockViewGroup.setStaticTransformationsEnabled(false);
2382         mMockViewGroup.drawChild(canvas, mMockTextView, 100);
2383         assertFalse(mMockViewGroup.isGetChildStaticTransformationCalled);
2384     }
2385 
2386     @UiThreadTest
2387     @Test
testStartActionModeForChildRespectsSubclassModeOnPrimary()2388     public void testStartActionModeForChildRespectsSubclassModeOnPrimary() {
2389         MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext);
2390         MockViewGroupSubclass vg = new MockViewGroupSubclass(mContext);
2391         vg.shouldReturnOwnTypelessActionMode = true;
2392         vgParent.addView(vg);
2393         vg.addView(mMockTextView);
2394 
2395         mMockTextView.startActionMode(NO_OP_ACTION_MODE_CALLBACK, ActionMode.TYPE_PRIMARY);
2396 
2397         assertTrue(vg.isStartActionModeForChildTypedCalled);
2398         assertTrue(vg.isStartActionModeForChildTypelessCalled);
2399         // Call should not bubble up as we have an intercepting implementation.
2400         assertFalse(vgParent.isStartActionModeForChildTypedCalled);
2401     }
2402 
2403     @UiThreadTest
2404     @Test
testStartActionModeForChildIgnoresSubclassModeOnFloating()2405     public void testStartActionModeForChildIgnoresSubclassModeOnFloating() {
2406         MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext);
2407         MockViewGroupSubclass vg = new MockViewGroupSubclass(mContext);
2408         vg.shouldReturnOwnTypelessActionMode = true;
2409         vgParent.addView(vg);
2410         vg.addView(mMockTextView);
2411 
2412         mMockTextView.startActionMode(NO_OP_ACTION_MODE_CALLBACK, ActionMode.TYPE_FLOATING);
2413 
2414         assertTrue(vg.isStartActionModeForChildTypedCalled);
2415         assertFalse(vg.isStartActionModeForChildTypelessCalled);
2416         // Call should bubble up as we have a floating type.
2417         assertTrue(vgParent.isStartActionModeForChildTypedCalled);
2418     }
2419 
2420     @UiThreadTest
2421     @Test
testStartActionModeForChildTypedBubblesUpToParent()2422     public void testStartActionModeForChildTypedBubblesUpToParent() {
2423         MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext);
2424         MockViewGroupSubclass vg = new MockViewGroupSubclass(mContext);
2425         vgParent.addView(vg);
2426         vg.addView(mMockTextView);
2427 
2428         mMockTextView.startActionMode(NO_OP_ACTION_MODE_CALLBACK, ActionMode.TYPE_FLOATING);
2429 
2430         assertTrue(vg.isStartActionModeForChildTypedCalled);
2431         assertTrue(vgParent.isStartActionModeForChildTypedCalled);
2432     }
2433 
2434     @UiThreadTest
2435     @Test
testStartActionModeForChildTypelessBubblesUpToParent()2436     public void testStartActionModeForChildTypelessBubblesUpToParent() {
2437         MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext);
2438         MockViewGroupSubclass vg = new MockViewGroupSubclass(mContext);
2439         vgParent.addView(vg);
2440         vg.addView(mMockTextView);
2441 
2442         mMockTextView.startActionMode(NO_OP_ACTION_MODE_CALLBACK);
2443 
2444         assertTrue(vg.isStartActionModeForChildTypedCalled);
2445         assertTrue(vg.isStartActionModeForChildTypelessCalled);
2446         assertTrue(vgParent.isStartActionModeForChildTypedCalled);
2447     }
2448 
2449     @UiThreadTest
2450     @Test
testTemporaryDetach()2451     public void testTemporaryDetach() {
2452         // [vgParent]
2453         //   - [viewParent1]
2454         //   - [viewParent1]
2455         //   - [mMockViewGroup]
2456         //     - [view1]
2457         //     - [view2]
2458         MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext);
2459         TemporaryDetachingMockView viewParent1 = new TemporaryDetachingMockView(mContext);
2460         TemporaryDetachingMockView viewParent2 = new TemporaryDetachingMockView(mContext);
2461         vgParent.addView(viewParent1);
2462         vgParent.addView(viewParent2);
2463         MockViewGroupSubclass vg = new MockViewGroupSubclass(mContext);
2464         vgParent.addView(vg);
2465         TemporaryDetachingMockView view1 = new TemporaryDetachingMockView(mContext);
2466         TemporaryDetachingMockView view2 = new TemporaryDetachingMockView(mContext);
2467         vg.addView(view1);
2468         vg.addView(view2);
2469 
2470         // Make sure that no View is temporarity detached in the initial state.
2471         assertFalse(viewParent1.isTemporarilyDetached());
2472         assertEquals(0, viewParent1.getDispatchStartTemporaryDetachCount());
2473         assertEquals(0, viewParent1.getDispatchFinishTemporaryDetachCount());
2474         assertEquals(0, viewParent1.getOnStartTemporaryDetachCount());
2475         assertEquals(0, viewParent1.getOnFinishTemporaryDetachCount());
2476         assertFalse(viewParent2.isTemporarilyDetached());
2477         assertEquals(0, viewParent2.getDispatchStartTemporaryDetachCount());
2478         assertEquals(0, viewParent2.getDispatchFinishTemporaryDetachCount());
2479         assertEquals(0, viewParent2.getOnStartTemporaryDetachCount());
2480         assertEquals(0, viewParent2.getOnFinishTemporaryDetachCount());
2481         assertFalse(view1.isTemporarilyDetached());
2482         assertEquals(0, view1.getDispatchStartTemporaryDetachCount());
2483         assertEquals(0, view1.getDispatchFinishTemporaryDetachCount());
2484         assertEquals(0, view1.getOnStartTemporaryDetachCount());
2485         assertEquals(0, view1.getOnFinishTemporaryDetachCount());
2486         assertFalse(view2.isTemporarilyDetached());
2487         assertEquals(0, view2.getDispatchStartTemporaryDetachCount());
2488         assertEquals(0, view2.getDispatchFinishTemporaryDetachCount());
2489         assertEquals(0, view2.getOnStartTemporaryDetachCount());
2490         assertEquals(0, view2.getOnFinishTemporaryDetachCount());
2491 
2492         // [vgParent]
2493         //   - [viewParent1]
2494         //   - [viewParent1]
2495         //   - [mMockViewGroup]           <- dispatchStartTemporaryDetach()
2496         //     - [view1]
2497         //     - [view2]
2498         vg.dispatchStartTemporaryDetach();
2499 
2500         assertFalse(viewParent1.isTemporarilyDetached());
2501         assertEquals(0, viewParent1.getDispatchStartTemporaryDetachCount());
2502         assertEquals(0, viewParent1.getDispatchFinishTemporaryDetachCount());
2503         assertEquals(0, viewParent1.getOnStartTemporaryDetachCount());
2504         assertEquals(0, viewParent1.getOnFinishTemporaryDetachCount());
2505         assertFalse(viewParent2.isTemporarilyDetached());
2506         assertEquals(0, viewParent2.getDispatchStartTemporaryDetachCount());
2507         assertEquals(0, viewParent2.getDispatchFinishTemporaryDetachCount());
2508         assertEquals(0, viewParent2.getOnStartTemporaryDetachCount());
2509         assertEquals(0, viewParent2.getOnFinishTemporaryDetachCount());
2510         assertTrue(view1.isTemporarilyDetached());
2511         assertEquals(1, view1.getDispatchStartTemporaryDetachCount());
2512         assertEquals(0, view1.getDispatchFinishTemporaryDetachCount());
2513         assertEquals(1, view1.getOnStartTemporaryDetachCount());
2514         assertEquals(0, view1.getOnFinishTemporaryDetachCount());
2515         assertTrue(view2.isTemporarilyDetached());
2516         assertEquals(1, view2.getDispatchStartTemporaryDetachCount());
2517         assertEquals(0, view2.getDispatchFinishTemporaryDetachCount());
2518         assertEquals(1, view2.getOnStartTemporaryDetachCount());
2519         assertEquals(0, view2.getOnFinishTemporaryDetachCount());
2520 
2521         // [vgParent]
2522         //   - [viewParent1]
2523         //   - [viewParent1]
2524         //   - [mMockViewGroup]           <- dispatchFinishTemporaryDetach()
2525         //     - [view1]
2526         //     - [view2]
2527         vg.dispatchFinishTemporaryDetach();
2528 
2529         assertFalse(viewParent1.isTemporarilyDetached());
2530         assertEquals(0, viewParent1.getDispatchStartTemporaryDetachCount());
2531         assertEquals(0, viewParent1.getDispatchFinishTemporaryDetachCount());
2532         assertEquals(0, viewParent1.getOnStartTemporaryDetachCount());
2533         assertEquals(0, viewParent1.getOnFinishTemporaryDetachCount());
2534         assertFalse(viewParent2.isTemporarilyDetached());
2535         assertEquals(0, viewParent2.getDispatchStartTemporaryDetachCount());
2536         assertEquals(0, viewParent2.getDispatchFinishTemporaryDetachCount());
2537         assertEquals(0, viewParent2.getOnStartTemporaryDetachCount());
2538         assertEquals(0, viewParent2.getOnFinishTemporaryDetachCount());
2539         assertFalse(view1.isTemporarilyDetached());
2540         assertEquals(1, view1.getDispatchStartTemporaryDetachCount());
2541         assertEquals(1, view1.getDispatchFinishTemporaryDetachCount());
2542         assertEquals(1, view1.getOnStartTemporaryDetachCount());
2543         assertEquals(1, view1.getOnFinishTemporaryDetachCount());
2544         assertFalse(view2.isTemporarilyDetached());
2545         assertEquals(1, view2.getDispatchStartTemporaryDetachCount());
2546         assertEquals(1, view2.getDispatchFinishTemporaryDetachCount());
2547         assertEquals(1, view2.getOnStartTemporaryDetachCount());
2548         assertEquals(1, view2.getOnFinishTemporaryDetachCount());
2549 
2550         // [vgParent]         <- dispatchStartTemporaryDetach()
2551         //   - [viewParent1]
2552         //   - [viewParent1]
2553         //   - [mMockViewGroup]
2554         //     - [view1]
2555         //     - [view2]
2556         vgParent.dispatchStartTemporaryDetach();
2557 
2558         assertTrue(viewParent1.isTemporarilyDetached());
2559         assertEquals(1, viewParent1.getDispatchStartTemporaryDetachCount());
2560         assertEquals(0, viewParent1.getDispatchFinishTemporaryDetachCount());
2561         assertEquals(1, viewParent1.getOnStartTemporaryDetachCount());
2562         assertEquals(0, viewParent1.getOnFinishTemporaryDetachCount());
2563         assertTrue(viewParent2.isTemporarilyDetached());
2564         assertEquals(1, viewParent2.getDispatchStartTemporaryDetachCount());
2565         assertEquals(0, viewParent2.getDispatchFinishTemporaryDetachCount());
2566         assertEquals(1, viewParent2.getOnStartTemporaryDetachCount());
2567         assertEquals(0, viewParent2.getOnFinishTemporaryDetachCount());
2568         assertTrue(view1.isTemporarilyDetached());
2569         assertEquals(2, view1.getDispatchStartTemporaryDetachCount());
2570         assertEquals(1, view1.getDispatchFinishTemporaryDetachCount());
2571         assertEquals(2, view1.getOnStartTemporaryDetachCount());
2572         assertEquals(1, view1.getOnFinishTemporaryDetachCount());
2573         assertTrue(view2.isTemporarilyDetached());
2574         assertEquals(2, view2.getDispatchStartTemporaryDetachCount());
2575         assertEquals(1, view2.getDispatchFinishTemporaryDetachCount());
2576         assertEquals(2, view2.getOnStartTemporaryDetachCount());
2577         assertEquals(1, view2.getOnFinishTemporaryDetachCount());
2578 
2579         // [vgParent]         <- dispatchFinishTemporaryDetach()
2580         //   - [viewParent1]
2581         //   - [viewParent1]
2582         //   - [mMockViewGroup]
2583         //     - [view1]
2584         //     - [view2]
2585         vgParent.dispatchFinishTemporaryDetach();
2586 
2587         assertFalse(viewParent1.isTemporarilyDetached());
2588         assertEquals(1, viewParent1.getDispatchStartTemporaryDetachCount());
2589         assertEquals(1, viewParent1.getDispatchFinishTemporaryDetachCount());
2590         assertEquals(1, viewParent1.getOnStartTemporaryDetachCount());
2591         assertEquals(1, viewParent1.getOnFinishTemporaryDetachCount());
2592         assertFalse(viewParent2.isTemporarilyDetached());
2593         assertEquals(1, viewParent2.getDispatchStartTemporaryDetachCount());
2594         assertEquals(1, viewParent2.getDispatchFinishTemporaryDetachCount());
2595         assertEquals(1, viewParent2.getOnStartTemporaryDetachCount());
2596         assertEquals(1, viewParent2.getOnFinishTemporaryDetachCount());
2597         assertFalse(view1.isTemporarilyDetached());
2598         assertEquals(2, view1.getDispatchStartTemporaryDetachCount());
2599         assertEquals(2, view1.getDispatchFinishTemporaryDetachCount());
2600         assertEquals(2, view1.getOnStartTemporaryDetachCount());
2601         assertEquals(2, view1.getOnFinishTemporaryDetachCount());
2602         assertFalse(view2.isTemporarilyDetached());
2603         assertEquals(2, view2.getDispatchStartTemporaryDetachCount());
2604         assertEquals(2, view2.getDispatchFinishTemporaryDetachCount());
2605         assertEquals(2, view2.getOnStartTemporaryDetachCount());
2606         assertEquals(2, view2.getOnFinishTemporaryDetachCount());
2607     }
2608 
2609     private static final ActionMode.Callback NO_OP_ACTION_MODE_CALLBACK =
2610             new ActionMode.Callback() {
2611                 @Override
2612                 public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
2613                     return false;
2614                 }
2615 
2616                 @Override
2617                 public void onDestroyActionMode(ActionMode mode) {}
2618 
2619                 @Override
2620                 public boolean onCreateActionMode(ActionMode mode, Menu menu) {
2621                     return false;
2622                 }
2623 
2624                 @Override
2625                 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
2626                     return false;
2627                 }
2628             };
2629 
2630     private static final ActionMode NO_OP_ACTION_MODE =
2631             new ActionMode() {
2632                 @Override
2633                 public void setTitle(CharSequence title) {}
2634 
2635                 @Override
2636                 public void setTitle(int resId) {}
2637 
2638                 @Override
2639                 public void setSubtitle(CharSequence subtitle) {}
2640 
2641                 @Override
2642                 public void setSubtitle(int resId) {}
2643 
2644                 @Override
2645                 public void setCustomView(View view) {}
2646 
2647                 @Override
2648                 public void invalidate() {}
2649 
2650                 @Override
2651                 public void finish() {}
2652 
2653                 @Override
2654                 public Menu getMenu() {
2655                     return null;
2656                 }
2657 
2658                 @Override
2659                 public CharSequence getTitle() {
2660                     return null;
2661                 }
2662 
2663                 @Override
2664                 public CharSequence getSubtitle() {
2665                     return null;
2666                 }
2667 
2668                 @Override
2669                 public View getCustomView() {
2670                     return null;
2671                 }
2672 
2673                 @Override
2674                 public MenuInflater getMenuInflater() {
2675                     return null;
2676                 }
2677             };
2678 
2679     private static class MockViewGroupSubclass extends ViewGroup {
2680         boolean isStartActionModeForChildTypedCalled = false;
2681         boolean isStartActionModeForChildTypelessCalled = false;
2682         boolean shouldReturnOwnTypelessActionMode = false;
2683 
MockViewGroupSubclass(Context context)2684         public MockViewGroupSubclass(Context context) {
2685             super(context);
2686         }
2687 
2688         @Override
startActionModeForChild(View originalView, ActionMode.Callback callback)2689         public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
2690             isStartActionModeForChildTypelessCalled = true;
2691             if (shouldReturnOwnTypelessActionMode) {
2692                 return NO_OP_ACTION_MODE;
2693             }
2694             return super.startActionModeForChild(originalView, callback);
2695         }
2696 
2697         @Override
startActionModeForChild( View originalView, ActionMode.Callback callback, int type)2698         public ActionMode startActionModeForChild(
2699                 View originalView, ActionMode.Callback callback, int type) {
2700             isStartActionModeForChildTypedCalled = true;
2701             return super.startActionModeForChild(originalView, callback, type);
2702         }
2703 
2704         @Override
onLayout(boolean changed, int l, int t, int r, int b)2705         protected void onLayout(boolean changed, int l, int t, int r, int b) {
2706             // no-op
2707         }
2708     }
2709 
2710     static public int resetRtlPropertiesCount;
2711     static public int resetResolvedLayoutDirectionCount;
2712     static public int resetResolvedTextDirectionCount;
2713     static public int resetResolvedTextAlignmentCount;
2714     static public int resetResolvedPaddingCount;
2715     static public int resetResolvedDrawablesCount;
2716 
2717 
clearRtlCounters()2718     private static void clearRtlCounters() {
2719         resetRtlPropertiesCount = 0;
2720         resetResolvedLayoutDirectionCount = 0;
2721         resetResolvedTextDirectionCount = 0;
2722         resetResolvedTextAlignmentCount = 0;
2723         resetResolvedPaddingCount = 0;
2724         resetResolvedDrawablesCount = 0;
2725     }
2726 
2727     @UiThreadTest
2728     @Test
testResetRtlProperties()2729     public void testResetRtlProperties() {
2730         clearRtlCounters();
2731 
2732         MockView2 v1 = new MockView2(mContext);
2733         MockView2 v2 = new MockView2(mContext);
2734 
2735         MockViewGroup v3 = new MockViewGroup(mContext);
2736         MockView2 v4 = new MockView2(mContext);
2737 
2738         v3.addView(v4);
2739         assertEquals(1, resetRtlPropertiesCount);
2740         assertEquals(1, resetResolvedLayoutDirectionCount);
2741         assertEquals(1, resetResolvedTextDirectionCount);
2742         assertEquals(1, resetResolvedTextAlignmentCount);
2743         assertEquals(1, resetResolvedPaddingCount);
2744         assertEquals(1, resetResolvedDrawablesCount);
2745 
2746         clearRtlCounters();
2747         mMockViewGroup.addView(v1);
2748         mMockViewGroup.addView(v2);
2749         mMockViewGroup.addView(v3);
2750 
2751         assertEquals(3, resetRtlPropertiesCount); // for v1 / v2 / v3 only
2752         assertEquals(4, resetResolvedLayoutDirectionCount); // for v1 / v2 / v3 / v4
2753         assertEquals(4, resetResolvedTextDirectionCount);
2754         assertEquals(3, resetResolvedTextAlignmentCount); // for v1 / v2 / v3 only
2755         assertEquals(4, resetResolvedPaddingCount);
2756         assertEquals(4, resetResolvedDrawablesCount);
2757 
2758         clearRtlCounters();
2759         mMockViewGroup.resetRtlProperties();
2760         assertEquals(1, resetRtlPropertiesCount); // for mMockViewGroup only
2761         assertEquals(5, resetResolvedLayoutDirectionCount); // for all
2762         assertEquals(5, resetResolvedTextDirectionCount);
2763         // for mMockViewGroup only as TextAlignment is not inherited (default is Gravity)
2764         assertEquals(1, resetResolvedTextAlignmentCount);
2765         assertEquals(5, resetResolvedPaddingCount);
2766         assertEquals(5, resetResolvedDrawablesCount);
2767     }
2768 
2769     @UiThreadTest
2770     @Test
testLayoutNotCalledWithSuppressLayoutTrue()2771     public void testLayoutNotCalledWithSuppressLayoutTrue() {
2772         mMockViewGroup.isRequestLayoutCalled = false;
2773         mMockViewGroup.suppressLayout(true);
2774         mMockViewGroup.layout(0, 0, 100, 100);
2775 
2776         assertTrue(mMockViewGroup.isLayoutSuppressed());
2777         assertFalse(mMockViewGroup.isOnLayoutCalled);
2778         assertFalse(mMockViewGroup.isRequestLayoutCalled);
2779     }
2780 
2781     @UiThreadTest
2782     @Test
testLayoutCalledAfterSettingBackSuppressLayoutToFalseTrue()2783     public void testLayoutCalledAfterSettingBackSuppressLayoutToFalseTrue() {
2784         mMockViewGroup.suppressLayout(true);
2785         mMockViewGroup.suppressLayout(false);
2786         mMockViewGroup.layout(0, 0, 100, 100);
2787 
2788         assertFalse(mMockViewGroup.isLayoutSuppressed());
2789         assertTrue(mMockViewGroup.isOnLayoutCalled);
2790     }
2791 
2792     @UiThreadTest
2793     @Test
testRequestLayoutCalledAfterSettingSuppressToFalseWhenItWasCalledWithTrue()2794     public void testRequestLayoutCalledAfterSettingSuppressToFalseWhenItWasCalledWithTrue() {
2795         mMockViewGroup.isRequestLayoutCalled = false;
2796         mMockViewGroup.suppressLayout(true);
2797         // now we call layout while in suppressed state
2798         mMockViewGroup.layout(0, 0, 100, 100);
2799         // then we undo suppressing. it should call requestLayout as we swallowed one layout call
2800         mMockViewGroup.suppressLayout(false);
2801 
2802         assertTrue(mMockViewGroup.isRequestLayoutCalled);
2803     }
2804 
2805     @UiThreadTest
2806     @Ignore("Turn on once ViewRootImpl.USE_NEW_INSETS is switched to true")
2807     @Test
testDispatchInsets_affectsChildren()2808     public void testDispatchInsets_affectsChildren() {
2809         View v1 = new View(mContext);
2810         mMockViewGroup.addView(v1);
2811 
2812         mMockViewGroup.setOnApplyWindowInsetsListener((v, insets) -> insets.inset(0, 0, 0, 10));
2813 
2814         OnApplyWindowInsetsListener listenerMock = mock(OnApplyWindowInsetsListener.class);
2815         v1.setOnApplyWindowInsetsListener(listenerMock);
2816 
2817         WindowInsets insets = new WindowInsets.Builder().setSystemWindowInsets(
2818                 Insets.of(10, 10, 10, 10)).build();
2819         mMockViewGroup.dispatchApplyWindowInsets(insets);
2820         verify(listenerMock).onApplyWindowInsets(any(),
2821                 eq(new WindowInsets.Builder()
2822                         .setSystemWindowInsets(Insets.of(10, 10, 10, 0)).build()));
2823     }
2824 
2825     @UiThreadTest
2826     @Ignore("Turn on once ViewRootImpl.USE_NEW_INSETS is switched to true")
2827     @Test
testDispatchInsets_doesntAffectSiblings()2828     public void testDispatchInsets_doesntAffectSiblings() {
2829         View v1 = new View(mContext);
2830         View v2 = new View(mContext);
2831         mMockViewGroup.addView(v1);
2832         mMockViewGroup.addView(v2);
2833 
2834         v1.setOnApplyWindowInsetsListener((v, insets) -> insets.inset(0, 0, 0, 10));
2835 
2836         OnApplyWindowInsetsListener listenerMock = mock(OnApplyWindowInsetsListener.class);
2837         v2.setOnApplyWindowInsetsListener(listenerMock);
2838 
2839         WindowInsets insets = new WindowInsets.Builder().setSystemWindowInsets(
2840                 Insets.of(10, 10, 10, 10)).build();
2841         mMockViewGroup.dispatchApplyWindowInsets(insets);
2842         verify(listenerMock).onApplyWindowInsets(any(),
2843                 eq(new WindowInsets.Builder()
2844                         .setSystemWindowInsets(Insets.of(10, 10, 10, 10)).build()));
2845     }
2846 
2847     @UiThreadTest
2848     @Ignore("Turn on once ViewRootImpl.USE_NEW_INSETS is switched to true")
2849     @Test
testDispatchInsets_doesntAffectParentSiblings()2850     public void testDispatchInsets_doesntAffectParentSiblings() {
2851         ViewGroup v1 = new MockViewGroup(mContext);
2852         View v11 = new View(mContext);
2853         View v2 = new View(mContext);
2854         mMockViewGroup.addView(v1);
2855         v1.addView(v11);
2856         mMockViewGroup.addView(v2);
2857 
2858         v11.setOnApplyWindowInsetsListener((v, insets) -> insets.inset(0, 0, 0, 10));
2859 
2860         OnApplyWindowInsetsListener listenerMock = mock(OnApplyWindowInsetsListener.class);
2861         v2.setOnApplyWindowInsetsListener(listenerMock);
2862 
2863         WindowInsets insets = new WindowInsets.Builder().setSystemWindowInsets(
2864                 Insets.of(10, 10, 10, 10)).build();
2865         mMockViewGroup.dispatchApplyWindowInsets(insets);
2866         verify(listenerMock).onApplyWindowInsets(any(),
2867                 eq(new WindowInsets.Builder()
2868                         .setSystemWindowInsets(Insets.of(10, 10, 10, 10)).build()));
2869     }
2870 
2871     @UiThreadTest
2872     @Ignore("Turn on once ViewRootImpl.USE_NEW_INSETS is switched to true")
2873     @Test
testDispatchInsets_consumeDoesntStopDispatch()2874     public void testDispatchInsets_consumeDoesntStopDispatch() {
2875         View v1 = new View(mContext);
2876         mMockViewGroup.addView(v1);
2877 
2878         mMockViewGroup.setOnApplyWindowInsetsListener(
2879                 (v, insets) -> insets.consumeSystemWindowInsets());
2880 
2881         OnApplyWindowInsetsListener listenerMock = mock(OnApplyWindowInsetsListener.class);
2882         v1.setOnApplyWindowInsetsListener(listenerMock);
2883 
2884         WindowInsets insets = new WindowInsets.Builder().setSystemWindowInsets(
2885                 Insets.of(10, 10, 10, 10)).build();
2886         mMockViewGroup.dispatchApplyWindowInsets(insets);
2887         verify(listenerMock).onApplyWindowInsets(any(),
2888                 eq(new WindowInsets.Builder().build()));
2889     }
2890 
2891     static class MockTextView extends TextView {
2892 
2893         public boolean isClearFocusCalled;
2894         public boolean isDispatchRestoreInstanceStateCalled;
2895         public int visibility;
2896         public boolean mIsRefreshDrawableStateCalled;
2897         public boolean isDrawCalled;
2898 
MockTextView(Context context)2899         public MockTextView(Context context) {
2900             super(context);
2901         }
2902 
2903         @Override
draw(Canvas canvas)2904         public void draw(Canvas canvas) {
2905             super.draw(canvas);
2906             isDrawCalled = true;
2907         }
2908 
2909         @Override
clearFocus()2910         public void clearFocus() {
2911             isClearFocusCalled = true;
2912             super.clearFocus();
2913         }
2914 
2915         @Override
dispatchKeyEvent(KeyEvent event)2916         public boolean dispatchKeyEvent(KeyEvent event) {
2917             return true;
2918         }
2919 
2920         @Override
dispatchRestoreInstanceState( SparseArray<Parcelable> container)2921         public void dispatchRestoreInstanceState(
2922                 SparseArray<Parcelable> container) {
2923             isDispatchRestoreInstanceStateCalled = true;
2924             super.dispatchRestoreInstanceState(container);
2925         }
2926 
2927         @Override
onTrackballEvent(MotionEvent event)2928         public boolean onTrackballEvent(MotionEvent event) {
2929             return true;
2930         }
2931 
2932         @Override
dispatchUnhandledMove(View focused, int direction)2933         public boolean dispatchUnhandledMove(View focused, int direction) {
2934             return true;
2935         }
2936 
2937         @Override
onWindowVisibilityChanged(int visibility)2938         public void onWindowVisibilityChanged(int visibility) {
2939             this.visibility = visibility;
2940             super.onWindowVisibilityChanged(visibility);
2941         }
2942 
2943         @Override
refreshDrawableState()2944         public void refreshDrawableState() {
2945             mIsRefreshDrawableStateCalled = true;
2946             super.refreshDrawableState();
2947         }
2948 
2949         @Override
dispatchTouchEvent(MotionEvent event)2950         public boolean dispatchTouchEvent(MotionEvent event) {
2951             super.dispatchTouchEvent(event);
2952             return true;
2953         }
2954 
2955         @Override
dispatchKeyEventPreIme(KeyEvent event)2956         public boolean dispatchKeyEventPreIme(KeyEvent event) {
2957             return true;
2958         }
2959 
2960         @Override
dispatchKeyShortcutEvent(KeyEvent event)2961         public boolean dispatchKeyShortcutEvent(KeyEvent event) {
2962             return true;
2963         }
2964     }
2965 
2966     static class MockViewGroup extends ViewGroup {
2967 
2968         public boolean isRecomputeViewAttributesCalled;
2969         public boolean isShowContextMenuForChildCalled;
2970         public boolean isShowContextMenuForChildCalledWithXYCoords;
2971         public boolean isRefreshDrawableStateCalled;
2972         public boolean isOnRestoreInstanceStateCalled;
2973         public boolean isOnCreateDrawableStateCalled;
2974         public boolean isOnInterceptTouchEventCalled;
2975         public boolean isOnRequestFocusInDescendantsCalled;
2976         public boolean isOnViewAddedCalled;
2977         public boolean isOnViewRemovedCalled;
2978         public boolean isFocusableViewAvailable;
2979         public boolean isDispatchDrawCalled;
2980         public boolean isRequestDisallowInterceptTouchEventCalled;
2981         public boolean isRequestTransparentRegionCalled;
2982         public boolean isGetChildStaticTransformationCalled;
2983         public int[] location;
2984         public int measureChildCalledTime;
2985         public boolean isOnAnimationEndCalled;
2986         public boolean isOnAnimationStartCalled;
2987         public int debugDepth;
2988         public int drawChildCalledTime;
2989         public Canvas canvas;
2990         public boolean isDrawableStateChangedCalled;
2991         public boolean isRequestLayoutCalled;
2992         public boolean isOnLayoutCalled;
2993         public boolean isOnDescendantInvalidatedCalled;
2994         public int left;
2995         public int top;
2996         public int right;
2997         public int bottom;
2998         public boolean returnActualFocusSearchResult;
2999 
MockViewGroup(Context context, AttributeSet attrs, int defStyle)3000         public MockViewGroup(Context context, AttributeSet attrs, int defStyle) {
3001             super(context, attrs, defStyle);
3002         }
3003 
MockViewGroup(Context context, AttributeSet attrs)3004         public MockViewGroup(Context context, AttributeSet attrs) {
3005             super(context, attrs);
3006         }
3007 
MockViewGroup(Context context)3008         public MockViewGroup(Context context) {
3009             super(context);
3010         }
3011 
3012         @Override
onLayout(boolean changed, int l, int t, int r, int b)3013         public void onLayout(boolean changed, int l, int t, int r, int b) {
3014             isOnLayoutCalled = true;
3015             left = l;
3016             top = t;
3017             right = r;
3018             bottom = b;
3019         }
3020 
3021         @Override
addViewInLayout(View child, int index, ViewGroup.LayoutParams params)3022         public boolean addViewInLayout(View child, int index,
3023                 ViewGroup.LayoutParams params) {
3024             return super.addViewInLayout(child, index, params);
3025         }
3026 
3027         @Override
addViewInLayout(View child, int index, ViewGroup.LayoutParams params, boolean preventRequestLayout)3028         public boolean addViewInLayout(View child, int index,
3029                 ViewGroup.LayoutParams params, boolean preventRequestLayout) {
3030             return super.addViewInLayout(child, index, params, preventRequestLayout);
3031         }
3032 
3033         @Override
attachLayoutAnimationParameters(View child, ViewGroup.LayoutParams params, int index, int count)3034         public void attachLayoutAnimationParameters(View child,
3035                 ViewGroup.LayoutParams params, int index, int count) {
3036             super.attachLayoutAnimationParameters(child, params, index, count);
3037         }
3038 
3039         @Override
attachViewToParent(View child, int index, LayoutParams params)3040         public void attachViewToParent(View child, int index,
3041                 LayoutParams params) {
3042             super.attachViewToParent(child, index, params);
3043         }
3044 
3045         @Override
canAnimate()3046         public boolean canAnimate() {
3047             return super.canAnimate();
3048         }
3049 
3050         @Override
checkLayoutParams(LayoutParams p)3051         public boolean checkLayoutParams(LayoutParams p) {
3052             return super.checkLayoutParams(p);
3053         }
3054 
3055         @Override
refreshDrawableState()3056         public void refreshDrawableState() {
3057             isRefreshDrawableStateCalled = true;
3058             super.refreshDrawableState();
3059         }
3060 
3061         @Override
cleanupLayoutState(View child)3062         public void cleanupLayoutState(View child) {
3063             super.cleanupLayoutState(child);
3064         }
3065 
3066         @Override
detachAllViewsFromParent()3067         public void detachAllViewsFromParent() {
3068             super.detachAllViewsFromParent();
3069         }
3070 
3071         @Override
detachViewFromParent(int index)3072         public void detachViewFromParent(int index) {
3073             super.detachViewFromParent(index);
3074         }
3075 
3076         @Override
detachViewFromParent(View child)3077         public void detachViewFromParent(View child) {
3078             super.detachViewFromParent(child);
3079         }
3080         @Override
3081 
detachViewsFromParent(int start, int count)3082         public void detachViewsFromParent(int start, int count) {
3083             super.detachViewsFromParent(start, count);
3084         }
3085 
3086         @Override
dispatchDraw(Canvas canvas)3087         public void dispatchDraw(Canvas canvas) {
3088             isDispatchDrawCalled = true;
3089             super.dispatchDraw(canvas);
3090             this.canvas = canvas;
3091         }
3092 
3093         @Override
dispatchFreezeSelfOnly(SparseArray<Parcelable> container)3094         public void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
3095             super.dispatchFreezeSelfOnly(container);
3096         }
3097 
3098         @Override
dispatchRestoreInstanceState( SparseArray<Parcelable> container)3099         public void dispatchRestoreInstanceState(
3100                 SparseArray<Parcelable> container) {
3101             super.dispatchRestoreInstanceState(container);
3102         }
3103 
3104         @Override
dispatchSaveInstanceState( SparseArray<Parcelable> container)3105         public void dispatchSaveInstanceState(
3106                 SparseArray<Parcelable> container) {
3107             super.dispatchSaveInstanceState(container);
3108         }
3109 
3110         @Override
dispatchSetPressed(boolean pressed)3111         public void dispatchSetPressed(boolean pressed) {
3112             super.dispatchSetPressed(pressed);
3113         }
3114 
3115         @Override
dispatchThawSelfOnly(SparseArray<Parcelable> container)3116         public void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
3117             super.dispatchThawSelfOnly(container);
3118         }
3119 
3120         @Override
onRestoreInstanceState(Parcelable state)3121         public void onRestoreInstanceState(Parcelable state) {
3122             isOnRestoreInstanceStateCalled = true;
3123             super.onRestoreInstanceState(state);
3124         }
3125 
3126         @Override
drawableStateChanged()3127         public void drawableStateChanged() {
3128             isDrawableStateChangedCalled = true;
3129             super.drawableStateChanged();
3130         }
3131 
3132         @Override
drawChild(Canvas canvas, View child, long drawingTime)3133         public boolean drawChild(Canvas canvas, View child, long drawingTime) {
3134             drawChildCalledTime++;
3135             return super.drawChild(canvas, child, drawingTime);
3136         }
3137 
3138         @Override
fitSystemWindows(Rect insets)3139         public boolean fitSystemWindows(Rect insets) {
3140             return super.fitSystemWindows(insets);
3141         }
3142 
3143         @Override
generateDefaultLayoutParams()3144         public LayoutParams generateDefaultLayoutParams() {
3145             return super.generateDefaultLayoutParams();
3146         }
3147 
3148         @Override
generateLayoutParams(LayoutParams p)3149         public LayoutParams generateLayoutParams(LayoutParams p) {
3150             return super.generateLayoutParams(p);
3151         }
3152 
3153         @Override
getChildDrawingOrder(int childCount, int i)3154         public int getChildDrawingOrder(int childCount, int i) {
3155             return super.getChildDrawingOrder(childCount, i);
3156         }
3157 
3158         @Override
getChildStaticTransformation(View child, Transformation t)3159         public boolean getChildStaticTransformation(View child,
3160                 Transformation t) {
3161             isGetChildStaticTransformationCalled = true;
3162             return super.getChildStaticTransformation(child, t);
3163         }
3164 
3165         @Override
measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec)3166         public void measureChild(View child, int parentWidthMeasureSpec,
3167                 int parentHeightMeasureSpec) {
3168             measureChildCalledTime++;
3169             super.measureChild(child, parentWidthMeasureSpec, parentHeightMeasureSpec);
3170         }
3171 
3172         @Override
measureChildren(int widthMeasureSpec, int heightMeasureSpec)3173         public void measureChildren(int widthMeasureSpec,
3174                 int heightMeasureSpec) {
3175             super.measureChildren(widthMeasureSpec, heightMeasureSpec);
3176         }
3177 
3178         @Override
measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed)3179         public void measureChildWithMargins(View child,
3180                 int parentWidthMeasureSpec, int widthUsed,
3181                 int parentHeightMeasureSpec, int heightUsed) {
3182             super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
3183                     parentHeightMeasureSpec, heightUsed);
3184         }
3185 
3186         @Override
onAnimationEnd()3187         public void onAnimationEnd() {
3188             isOnAnimationEndCalled = true;
3189             super.onAnimationEnd();
3190         }
3191 
3192         @Override
onAnimationStart()3193         public void onAnimationStart() {
3194             super.onAnimationStart();
3195             isOnAnimationStartCalled = true;
3196         }
3197 
3198         @Override
onCreateDrawableState(int extraSpace)3199         public int[] onCreateDrawableState(int extraSpace) {
3200             isOnCreateDrawableStateCalled = true;
3201             return super.onCreateDrawableState(extraSpace);
3202         }
3203 
3204         @Override
onInterceptTouchEvent(MotionEvent ev)3205         public boolean onInterceptTouchEvent(MotionEvent ev) {
3206             isOnInterceptTouchEventCalled = true;
3207             return super.onInterceptTouchEvent(ev);
3208         }
3209 
3210         @Override
onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect)3211         public boolean onRequestFocusInDescendants(int direction,
3212                 Rect previouslyFocusedRect) {
3213             isOnRequestFocusInDescendantsCalled = true;
3214             return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
3215         }
3216 
3217         @Override
onViewAdded(View child)3218         public void onViewAdded(View child) {
3219             isOnViewAddedCalled = true;
3220             super.onViewAdded(child);
3221         }
3222 
3223         @Override
onViewRemoved(View child)3224         public void onViewRemoved(View child) {
3225             isOnViewRemovedCalled = true;
3226             super.onViewRemoved(child);
3227         }
3228 
3229         @Override
recomputeViewAttributes(View child)3230         public void recomputeViewAttributes(View child) {
3231             isRecomputeViewAttributesCalled = true;
3232             super.recomputeViewAttributes(child);
3233         }
3234 
3235         @Override
removeDetachedView(View child, boolean animate)3236         public void removeDetachedView(View child, boolean animate) {
3237             super.removeDetachedView(child, animate);
3238         }
3239 
3240         @Override
showContextMenuForChild(View originalView)3241         public boolean showContextMenuForChild(View originalView) {
3242             isShowContextMenuForChildCalled = true;
3243             return super.showContextMenuForChild(originalView);
3244         }
3245 
3246         @Override
showContextMenuForChild(View originalView, float x, float y)3247         public boolean showContextMenuForChild(View originalView, float x, float y) {
3248             isShowContextMenuForChildCalledWithXYCoords = true;
3249             return super.showContextMenuForChild(originalView, x, y);
3250         }
3251 
3252         @Override
isInTouchMode()3253         public boolean isInTouchMode() {
3254             super.isInTouchMode();
3255             return false;
3256         }
3257 
3258         @Override
focusableViewAvailable(View v)3259         public void focusableViewAvailable(View v) {
3260             isFocusableViewAvailable = true;
3261             super.focusableViewAvailable(v);
3262         }
3263 
3264         @Override
focusSearch(View focused, int direction)3265         public View focusSearch(View focused, int direction) {
3266             if (returnActualFocusSearchResult) {
3267                 return super.focusSearch(focused, direction);
3268             } else {
3269                 super.focusSearch(focused, direction);
3270                 return focused;
3271             }
3272         }
3273 
3274         @Override
requestDisallowInterceptTouchEvent(boolean disallowIntercept)3275         public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
3276             isRequestDisallowInterceptTouchEventCalled = true;
3277             super.requestDisallowInterceptTouchEvent(disallowIntercept);
3278         }
3279 
3280         @Override
requestTransparentRegion(View child)3281         public void requestTransparentRegion(View child) {
3282             isRequestTransparentRegionCalled = true;
3283             super.requestTransparentRegion(child);
3284         }
3285 
3286         @Override
debug(int depth)3287         public void debug(int depth) {
3288             debugDepth = depth;
3289             super.debug(depth);
3290         }
3291 
3292         @Override
requestLayout()3293         public void requestLayout() {
3294             isRequestLayoutCalled = true;
3295             super.requestLayout();
3296         }
3297 
3298         @Override
setStaticTransformationsEnabled(boolean enabled)3299         public void setStaticTransformationsEnabled(boolean enabled) {
3300             super.setStaticTransformationsEnabled(enabled);
3301         }
3302 
3303         @Override
resetRtlProperties()3304         public void resetRtlProperties() {
3305             super.resetRtlProperties();
3306             resetRtlPropertiesCount++;
3307         }
3308 
3309         @Override
resetResolvedLayoutDirection()3310         public void resetResolvedLayoutDirection() {
3311             super.resetResolvedLayoutDirection();
3312             resetResolvedLayoutDirectionCount++;
3313         }
3314 
3315         @Override
resetResolvedTextDirection()3316         public void resetResolvedTextDirection() {
3317             super.resetResolvedTextDirection();
3318             resetResolvedTextDirectionCount++;
3319         }
3320 
3321         @Override
resetResolvedTextAlignment()3322         public void resetResolvedTextAlignment() {
3323             super.resetResolvedTextAlignment();
3324             resetResolvedTextAlignmentCount++;
3325         }
3326 
3327         @Override
resetResolvedPadding()3328         public void resetResolvedPadding() {
3329             super.resetResolvedPadding();
3330             resetResolvedPaddingCount++;
3331         }
3332 
3333         @Override
resetResolvedDrawables()3334         protected void resetResolvedDrawables() {
3335             super.resetResolvedDrawables();
3336             resetResolvedDrawablesCount++;
3337         }
3338 
3339         @Override
onDescendantInvalidated(@onNull View child, @NonNull View target)3340         public void onDescendantInvalidated(@NonNull View child, @NonNull View target) {
3341             isOnDescendantInvalidatedCalled = true;
3342             super.onDescendantInvalidated(child, target);
3343         }
3344 
3345         @Override
setChildrenDrawnWithCacheEnabled(boolean enabled)3346         public void setChildrenDrawnWithCacheEnabled(boolean enabled) {
3347             super.setChildrenDrawnWithCacheEnabled(enabled);
3348         }
3349 
3350         @Override
isChildrenDrawnWithCacheEnabled()3351         public boolean isChildrenDrawnWithCacheEnabled() {
3352             return super.isChildrenDrawnWithCacheEnabled();
3353         }
3354     }
3355 
3356     static class MockView2 extends View {
3357 
MockView2(Context context)3358         public MockView2(Context context) {
3359             super(context);
3360         }
3361 
MockView2(Context context, AttributeSet attrs)3362         public MockView2(Context context, AttributeSet attrs) {
3363             super(context, attrs);
3364         }
3365 
MockView2(Context context, AttributeSet attrs, int defStyle)3366         public MockView2(Context context, AttributeSet attrs, int defStyle) {
3367             super(context, attrs, defStyle);
3368         }
3369 
3370         @Override
resetRtlProperties()3371         public void resetRtlProperties() {
3372             super.resetRtlProperties();
3373             resetRtlPropertiesCount++;
3374         }
3375 
3376         @Override
resetResolvedLayoutDirection()3377         public void resetResolvedLayoutDirection() {
3378             super.resetResolvedLayoutDirection();
3379             resetResolvedLayoutDirectionCount++;
3380         }
3381 
3382         @Override
resetResolvedTextDirection()3383         public void resetResolvedTextDirection() {
3384             super.resetResolvedTextDirection();
3385             resetResolvedTextDirectionCount++;
3386         }
3387 
3388         @Override
resetResolvedTextAlignment()3389         public void resetResolvedTextAlignment() {
3390             super.resetResolvedTextAlignment();
3391             resetResolvedTextAlignmentCount++;
3392         }
3393 
3394         @Override
resetResolvedPadding()3395         public void resetResolvedPadding() {
3396             super.resetResolvedPadding();
3397             resetResolvedPaddingCount++;
3398         }
3399 
3400         @Override
resetResolvedDrawables()3401         protected void resetResolvedDrawables() {
3402             super.resetResolvedDrawables();
3403             resetResolvedDrawablesCount++;
3404         }
3405     }
3406 
3407     static final class TemporaryDetachingMockView extends View {
3408         private int mDispatchStartTemporaryDetachCount = 0;
3409         private int mDispatchFinishTemporaryDetachCount = 0;
3410         private int mOnStartTemporaryDetachCount = 0;
3411         private int mOnFinishTemporaryDetachCount = 0;
3412 
TemporaryDetachingMockView(Context context)3413         public TemporaryDetachingMockView(Context context) {
3414             super(context);
3415         }
3416 
3417         @Override
dispatchStartTemporaryDetach()3418         public void dispatchStartTemporaryDetach() {
3419             super.dispatchStartTemporaryDetach();
3420             mDispatchStartTemporaryDetachCount += 1;
3421         }
3422 
3423         @Override
dispatchFinishTemporaryDetach()3424         public void dispatchFinishTemporaryDetach() {
3425             super.dispatchFinishTemporaryDetach();
3426             mDispatchFinishTemporaryDetachCount += 1;
3427         }
3428 
3429         @Override
onStartTemporaryDetach()3430         public void onStartTemporaryDetach() {
3431             super.onStartTemporaryDetach();
3432             mOnStartTemporaryDetachCount += 1;
3433         }
3434 
3435         @Override
onFinishTemporaryDetach()3436         public void onFinishTemporaryDetach() {
3437             super.onFinishTemporaryDetach();
3438             mOnFinishTemporaryDetachCount += 1;
3439         }
3440 
getDispatchStartTemporaryDetachCount()3441         public int getDispatchStartTemporaryDetachCount() {
3442             return mDispatchStartTemporaryDetachCount;
3443         }
3444 
getDispatchFinishTemporaryDetachCount()3445         public int getDispatchFinishTemporaryDetachCount() {
3446             return mDispatchFinishTemporaryDetachCount;
3447         }
3448 
getOnStartTemporaryDetachCount()3449         public int getOnStartTemporaryDetachCount() {
3450             return mOnStartTemporaryDetachCount;
3451         }
3452 
getOnFinishTemporaryDetachCount()3453         public int getOnFinishTemporaryDetachCount() {
3454             return mOnFinishTemporaryDetachCount;
3455         }
3456     }
3457 
3458     public static class ScrollTestView extends ViewGroup {
ScrollTestView(Context context)3459         public ScrollTestView(Context context) {
3460             super(context);
3461         }
3462 
3463         @Override
onLayout(boolean changed, int l, int t, int r, int b)3464         protected void onLayout(boolean changed, int l, int t, int r, int b) {
3465 
3466         }
3467 
3468         @Override
awakenScrollBars()3469         public boolean awakenScrollBars() {
3470             return super.awakenScrollBars();
3471         }
3472 
3473         @Override
computeHorizontalScrollRange()3474         public int computeHorizontalScrollRange() {
3475             return super.computeHorizontalScrollRange();
3476         }
3477 
3478         @Override
computeHorizontalScrollExtent()3479         public int computeHorizontalScrollExtent() {
3480             return super.computeHorizontalScrollExtent();
3481         }
3482 
3483         @Override
computeVerticalScrollRange()3484         public int computeVerticalScrollRange() {
3485             return super.computeVerticalScrollRange();
3486         }
3487 
3488         @Override
computeVerticalScrollExtent()3489         public int computeVerticalScrollExtent() {
3490             return super.computeVerticalScrollExtent();
3491         }
3492 
3493         @Override
getHorizontalScrollbarHeight()3494         protected int getHorizontalScrollbarHeight() {
3495             return super.getHorizontalScrollbarHeight();
3496         }
3497     }
3498 
3499     @Override
setResult(int resultCode)3500     public void setResult(int resultCode) {
3501         synchronized (mSync) {
3502             mSync.mHasNotify = true;
3503             mSync.notify();
3504             mResultCode = resultCode;
3505         }
3506     }
3507 }
3508