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