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