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