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