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.widget.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.assertTrue;
     24 import static org.junit.Assert.fail;
     25 
     26 import android.app.Activity;
     27 import android.app.Instrumentation;
     28 import android.content.Context;
     29 import android.content.res.Resources;
     30 import android.graphics.Color;
     31 import android.graphics.Rect;
     32 import android.graphics.drawable.Drawable;
     33 import android.test.ViewAsserts;
     34 import android.util.AttributeSet;
     35 import android.util.Xml;
     36 import android.view.Gravity;
     37 import android.view.View;
     38 import android.view.View.MeasureSpec;
     39 import android.view.ViewGroup;
     40 import android.view.ViewTreeObserver;
     41 import android.widget.AbsoluteLayout;
     42 import android.widget.LinearLayout;
     43 import android.widget.LinearLayout.LayoutParams;
     44 import android.widget.ListView;
     45 import android.widget.TextView;
     46 import android.widget.cts.util.TestUtils;
     47 
     48 import androidx.annotation.ColorInt;
     49 import androidx.annotation.Nullable;
     50 import androidx.test.InstrumentationRegistry;
     51 import androidx.test.annotation.UiThreadTest;
     52 import androidx.test.filters.MediumTest;
     53 import androidx.test.rule.ActivityTestRule;
     54 import androidx.test.runner.AndroidJUnit4;
     55 
     56 import com.android.compatibility.common.util.WidgetTestUtils;
     57 
     58 import org.junit.Before;
     59 import org.junit.Rule;
     60 import org.junit.Test;
     61 import org.junit.runner.RunWith;
     62 import org.xmlpull.v1.XmlPullParser;
     63 
     64 import java.util.concurrent.CountDownLatch;
     65 import java.util.concurrent.TimeUnit;
     66 
     67 /**
     68  * Test {@link LinearLayout}.
     69  */
     70 @MediumTest
     71 @RunWith(AndroidJUnit4.class)
     72 public class LinearLayoutTest {
     73     private Instrumentation mInstrumentation;
     74     private Activity mActivity;
     75 
     76     @Rule
     77     public ActivityTestRule<LinearLayoutCtsActivity> mActivityRule =
     78             new ActivityTestRule<>(LinearLayoutCtsActivity.class);
     79 
     80     @Before
     81     public void setup() {
     82         mInstrumentation = InstrumentationRegistry.getInstrumentation();
     83         mActivity = mActivityRule.getActivity();
     84     }
     85 
     86     @Test
     87     public void testConstructor() {
     88         new LinearLayout(mActivity);
     89 
     90         new LinearLayout(mActivity, null);
     91 
     92         XmlPullParser parser = mActivity.getResources().getXml(R.layout.linearlayout_layout);
     93         AttributeSet attrs = Xml.asAttributeSet(parser);
     94         new LinearLayout(mActivity, attrs);
     95     }
     96 
     97     @Test(expected=NullPointerException.class)
     98     public void testConstructorNullContext() {
     99         new LinearLayout(null, null);
    100     }
    101 
    102     @UiThreadTest
    103     @Test
    104     public void testAccessBaselineAligned() {
    105         LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_empty);
    106         parent.setBaselineAligned(true);
    107         assertTrue(parent.isBaselineAligned());
    108 
    109         parent.setBaselineAligned(false);
    110         assertFalse(parent.isBaselineAligned());
    111 
    112         // android:baselineAligned="false" in LinearLayout weightsum
    113         parent = (LinearLayout) mActivity.findViewById(R.id.linear_weightsum);
    114         assertFalse(parent.isBaselineAligned());
    115 
    116         // default mBaselineAligned is true.
    117         parent = (LinearLayout) mActivity.findViewById(R.id.linear_horizontal);
    118         assertTrue(parent.isBaselineAligned());
    119 
    120         // default mBaselineAligned is true.
    121         // Only applicable if {@link #mOrientation} is horizontal
    122         parent = (LinearLayout) mActivity.findViewById(R.id.linear_vertical);
    123         assertTrue(parent.isBaselineAligned());
    124     }
    125 
    126     @UiThreadTest
    127     @Test
    128     public void testGetBaseline() {
    129         LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_empty);
    130 
    131         ListView lv1 = new ListView(mActivity);
    132         parent.addView(lv1);
    133         assertEquals(-1, parent.getBaseline());
    134 
    135         ListView lv2 = new ListView(mActivity);
    136         parent.addView(lv2);
    137         parent.setBaselineAlignedChildIndex(1);
    138         try {
    139             parent.getBaseline();
    140             fail("LinearLayout.getBaseline() should throw exception here.");
    141         } catch (RuntimeException e) {
    142         }
    143 
    144         ListView lv3 = new MockListView(mActivity);
    145         parent.addView(lv3);
    146         parent.setBaselineAlignedChildIndex(2);
    147         assertEquals(lv3.getBaseline(), parent.getBaseline());
    148     }
    149 
    150     @UiThreadTest
    151     @Test
    152     public void testAccessBaselineAlignedChildIndex() {
    153         LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_empty);
    154 
    155         // set BaselineAlignedChildIndex
    156         ListView lv1 = new ListView(mActivity);
    157         ListView lv2 = new ListView(mActivity);
    158         ListView lv3 = new ListView(mActivity);
    159         parent.addView(lv1);
    160         parent.addView(lv2);
    161         parent.addView(lv3);
    162         parent.setBaselineAlignedChildIndex(1);
    163         assertEquals(1, parent.getBaselineAlignedChildIndex());
    164 
    165         parent.setBaselineAlignedChildIndex(2);
    166         assertEquals(2, parent.getBaselineAlignedChildIndex());
    167 
    168         try {
    169             parent.setBaselineAlignedChildIndex(-1);
    170             fail("LinearLayout should throw IllegalArgumentException here.");
    171         } catch (IllegalArgumentException e) {
    172         }
    173         try {
    174             parent.setBaselineAlignedChildIndex(3);
    175             fail("LinearLayout should throw IllegalArgumentException here.");
    176         } catch (IllegalArgumentException e) {
    177         }
    178 
    179         parent = (LinearLayout) mActivity.findViewById(R.id.linear_baseline_aligned_child_index);
    180         assertEquals(1, parent.getBaselineAlignedChildIndex());
    181     }
    182 
    183     /**
    184      * weightsum is a horizontal LinearLayout. There are three children in it.
    185      */
    186     @Test
    187     public void testAccessWeightSum() {
    188         LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_weightsum);
    189         TextView weight02 = (TextView) parent.findViewById(R.id.weight_0_2);
    190         TextView weight05 = (TextView) parent.findViewById(R.id.weight_0_5);
    191         TextView weight03 = (TextView) parent.findViewById(R.id.weight_0_3);
    192 
    193         assertNotNull(parent);
    194         assertNotNull(weight02);
    195         assertNotNull(weight05);
    196         assertNotNull(weight03);
    197 
    198         assertEquals(mActivity.getResources().getString(R.string.horizontal_text_1),
    199                 weight02.getText().toString());
    200         assertEquals(mActivity.getResources().getString(R.string.horizontal_text_2),
    201                 weight05.getText().toString());
    202         assertEquals(mActivity.getResources().getString(R.string.horizontal_text_3),
    203                 weight03.getText().toString());
    204 
    205         assertEquals(LinearLayout.HORIZONTAL, parent.getOrientation());
    206         assertEquals(1.0f, parent.getWeightSum(), 0.0f);
    207 
    208         int parentWidth = parent.getWidth();
    209         assertEquals(Math.ceil(parentWidth * 0.2), weight02.getWidth(), 1.0);
    210         assertEquals(Math.ceil(parentWidth * 0.5), weight05.getWidth(), 1.0);
    211         assertEquals(Math.ceil(parentWidth * 0.3), weight03.getWidth(), 1.0);
    212     }
    213 
    214     @UiThreadTest
    215     @Test
    216     public void testWeightDistribution() {
    217         LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_empty);
    218 
    219         for (int i = 0; i < 3; i++) {
    220             parent.addView(new View(mActivity), new LayoutParams(0, 0, 1));
    221         }
    222 
    223         int size = 100;
    224         int spec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
    225 
    226         for (int i = 0; i < 3; i++) {
    227             View child = parent.getChildAt(i);
    228             LayoutParams lp = (LayoutParams) child.getLayoutParams();
    229             lp.height = 0;
    230             lp.width = LayoutParams.MATCH_PARENT;
    231             child.setLayoutParams(lp);
    232         }
    233         parent.setOrientation(LinearLayout.VERTICAL);
    234         parent.measure(spec, spec);
    235         parent.layout(0, 0, size, size);
    236         assertEquals(100, parent.getWidth());
    237         assertEquals(100, parent.getChildAt(0).getWidth());
    238         assertEquals(100, parent.getChildAt(1).getWidth());
    239         assertEquals(100, parent.getChildAt(2).getWidth());
    240         assertEquals(100, parent.getHeight());
    241         assertEquals(33, parent.getChildAt(0).getHeight());
    242         assertEquals(33, parent.getChildAt(1).getHeight());
    243         assertEquals(34, parent.getChildAt(2).getHeight());
    244 
    245         for (int i = 0; i < 3; i++) {
    246             View child = parent.getChildAt(i);
    247             LayoutParams lp = (LayoutParams) child.getLayoutParams();
    248             lp.height = LayoutParams.MATCH_PARENT;
    249             lp.width = 0;
    250             child.setLayoutParams(lp);
    251         }
    252         parent.setOrientation(LinearLayout.HORIZONTAL);
    253         parent.measure(spec, spec);
    254         parent.layout(0, 0, size, size);
    255         assertEquals(100, parent.getWidth());
    256         assertEquals(33, parent.getChildAt(0).getWidth());
    257         assertEquals(33, parent.getChildAt(1).getWidth());
    258         assertEquals(34, parent.getChildAt(2).getWidth());
    259         assertEquals(100, parent.getHeight());
    260         assertEquals(100, parent.getChildAt(0).getHeight());
    261         assertEquals(100, parent.getChildAt(1).getHeight());
    262         assertEquals(100, parent.getChildAt(2).getHeight());
    263     }
    264 
    265     @UiThreadTest
    266     @Test
    267     public void testGenerateLayoutParams() {
    268         ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(320, 240);
    269         MockLinearLayout parent = (MockLinearLayout) mActivity.findViewById(R.id.linear_custom);
    270         LayoutParams layoutParams1 = parent.generateLayoutParams(lp);
    271         assertEquals(320, layoutParams1.width);
    272         assertEquals(240, layoutParams1.height);
    273     }
    274 
    275     @UiThreadTest
    276     @Test
    277     public void testCheckLayoutParams() {
    278         MockLinearLayout parent = (MockLinearLayout) mActivity.findViewById(R.id.linear_custom);
    279 
    280         ViewGroup.LayoutParams params = new AbsoluteLayout.LayoutParams(240, 320, 0, 0);
    281         assertFalse(parent.checkLayoutParams(params));
    282 
    283         params = new LinearLayout.LayoutParams(240, 320);
    284         assertTrue(parent.checkLayoutParams(params));
    285     }
    286 
    287     @UiThreadTest
    288     @Test
    289     public void testGenerateDefaultLayoutParams() {
    290         MockLinearLayout parent = (MockLinearLayout) mActivity.findViewById(R.id.linear_custom);
    291 
    292         parent.setOrientation(LinearLayout.HORIZONTAL);
    293         ViewGroup.LayoutParams param = parent.generateDefaultLayoutParams();
    294         assertNotNull(param);
    295         assertTrue(param instanceof LinearLayout.LayoutParams);
    296         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, param.width);
    297         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, param.height);
    298 
    299         parent.setOrientation(LinearLayout.VERTICAL);
    300         param = parent.generateDefaultLayoutParams();
    301         assertNotNull(param);
    302         assertTrue(param instanceof LinearLayout.LayoutParams);
    303         assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, param.width);
    304         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, param.height);
    305 
    306         parent.setOrientation(-1);
    307         assertNull(parent.generateDefaultLayoutParams());
    308     }
    309 
    310     @UiThreadTest
    311     @Test
    312     public void testGenerateLayoutParamsFromMarginParams() {
    313         MockLinearLayout parent = (MockLinearLayout) mActivity.findViewById(R.id.linear_custom);
    314 
    315         ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(3, 5);
    316         lp.leftMargin = 1;
    317         lp.topMargin = 2;
    318         lp.rightMargin = 3;
    319         lp.bottomMargin = 4;
    320         LinearLayout.LayoutParams generated = parent.generateLayoutParams(lp);
    321         assertNotNull(generated);
    322         assertEquals(3, generated.width);
    323         assertEquals(5, generated.height);
    324 
    325         assertEquals(1, generated.leftMargin);
    326         assertEquals(2, generated.topMargin);
    327         assertEquals(3, generated.rightMargin);
    328         assertEquals(4, generated.bottomMargin);
    329     }
    330 
    331     /**
    332      * layout of horizontal LinearLayout.
    333      * ----------------------------------------------------
    334      * | ------------ |                 |                 |
    335      * | | top view | | --------------- |                 |
    336      * | |          | | | center view | | --------------- |
    337      * | ------------ | |             | | | bottom view | |
    338      * |              | --------------- | |             | |
    339      * |     parent   |                 | --------------- |
    340      * ----------------------------------------------------
    341      */
    342     @Test
    343     public void testLayoutHorizontal() {
    344         LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_horizontal);
    345         TextView topView = (TextView) mActivity.findViewById(R.id.gravity_top);
    346         TextView centerView = (TextView) mActivity.findViewById(R.id.gravity_center_vertical);
    347         TextView bottomView = (TextView) mActivity.findViewById(R.id.gravity_bottom);
    348 
    349         assertNotNull(parent);
    350         assertNotNull(topView);
    351         assertNotNull(centerView);
    352         assertNotNull(bottomView);
    353 
    354         assertEquals(mActivity.getResources().getString(R.string.horizontal_text_1),
    355                 topView.getText().toString());
    356         assertEquals(mActivity.getResources().getString(R.string.horizontal_text_2),
    357                 centerView.getText().toString());
    358         assertEquals(mActivity.getResources().getString(R.string.horizontal_text_3),
    359                 bottomView.getText().toString());
    360 
    361         assertEquals(LinearLayout.HORIZONTAL, parent.getOrientation());
    362 
    363         ViewAsserts.assertTopAligned(parent, topView);
    364         ViewAsserts.assertVerticalCenterAligned(parent, centerView);
    365         ViewAsserts.assertBottomAligned(parent, bottomView);
    366 
    367         assertEquals(0, topView.getTop());
    368         assertEquals(topView.getHeight(), topView.getBottom());
    369         assertEquals(0, topView.getLeft());
    370         assertEquals(centerView.getLeft(), topView.getRight());
    371 
    372         int offset = (parent.getHeight() - centerView.getHeight()) / 2;
    373         assertEquals(offset, centerView.getTop());
    374         assertEquals(offset + centerView.getHeight(), centerView.getBottom());
    375         assertEquals(topView.getRight(), centerView.getLeft());
    376         assertEquals(bottomView.getLeft(), centerView.getRight());
    377 
    378         assertEquals(parent.getHeight() - bottomView.getHeight(), bottomView.getTop());
    379         assertEquals(parent.getHeight(), bottomView.getBottom());
    380         assertEquals(centerView.getRight(), bottomView.getLeft());
    381         assertEquals(parent.getWidth(), bottomView.getRight());
    382     }
    383 
    384     /**
    385      * layout of vertical LinearLayout.
    386      * -----------------------------------
    387      * | -------------                   |
    388      * | | left view |                   |
    389      * | -------------                   |
    390      * | - - - - - - - - - - - - - - - - |
    391      * |        ---------------          |
    392      * |        | center view |          |
    393      * |        ---------------          |
    394      * | - - - - - - - - - - - - - - - - |
    395      * |                  -------------- |
    396      * | parent           | right view | |
    397      * |                  -------------- |
    398      * -----------------------------------
    399      */
    400     @Test
    401     public void testLayoutVertical() {
    402         LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_vertical);
    403         TextView leftView = (TextView) mActivity.findViewById(R.id.gravity_left);
    404         TextView centerView = (TextView) mActivity.findViewById(R.id.gravity_center_horizontal);
    405         TextView rightView = (TextView) mActivity.findViewById(R.id.gravity_right);
    406 
    407         assertNotNull(parent);
    408         assertNotNull(leftView);
    409         assertNotNull(centerView);
    410         assertNotNull(rightView);
    411 
    412         assertEquals(mActivity.getResources().getString(R.string.vertical_text_1),
    413                 leftView.getText().toString());
    414         assertEquals(mActivity.getResources().getString(R.string.vertical_text_2),
    415                 centerView.getText().toString());
    416         assertEquals(mActivity.getResources().getString(R.string.vertical_text_3),
    417                 rightView.getText().toString());
    418 
    419         assertEquals(LinearLayout.VERTICAL, parent.getOrientation());
    420 
    421         ViewAsserts.assertLeftAligned(parent, leftView);
    422         ViewAsserts.assertHorizontalCenterAligned(parent, centerView);
    423         ViewAsserts.assertRightAligned(parent, rightView);
    424 
    425         assertEquals(0, leftView.getTop());
    426         assertEquals(centerView.getTop(), leftView.getBottom());
    427         assertEquals(0, leftView.getLeft());
    428         assertEquals(leftView.getWidth(), leftView.getRight());
    429 
    430         int offset = (parent.getWidth() - centerView.getWidth()) / 2;
    431         assertEquals(leftView.getBottom(), centerView.getTop());
    432         assertEquals(rightView.getTop(), centerView.getBottom());
    433         assertEquals(offset, centerView.getLeft());
    434         assertEquals(offset + centerView.getWidth(), centerView.getRight());
    435 
    436         assertEquals(centerView.getBottom(), rightView.getTop());
    437         assertEquals(parent.getHeight(), rightView.getBottom());
    438         assertEquals(parent.getWidth() - rightView.getWidth(), rightView.getLeft());
    439         assertEquals(parent.getWidth(), rightView.getRight());
    440     }
    441 
    442     @Test
    443     public void testVerticalCenterGravityOnHorizontalLayout() throws Throwable {
    444         LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_weightsum);
    445         TextView leftView = (TextView) parent.findViewById(R.id.weight_0_2);
    446         TextView centerView = (TextView) parent.findViewById(R.id.weight_0_5);
    447         TextView rightView = (TextView) parent.findViewById(R.id.weight_0_3);
    448 
    449         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    450                 () -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
    451 
    452         int originalLeftViewLeft = leftView.getLeft();
    453         int originalLeftViewRight = leftView.getRight();
    454         int originalCenterViewLeft = centerView.getLeft();
    455         int originalCenterViewRight = centerView.getRight();
    456         int originalRightViewLeft = rightView.getLeft();
    457         int originalRightViewRight = rightView.getRight();
    458 
    459         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    460                 () -> parent.setVerticalGravity(Gravity.CENTER_VERTICAL));
    461 
    462         assertEquals(Gravity.CENTER_VERTICAL, parent.getGravity() & Gravity.VERTICAL_GRAVITY_MASK);
    463 
    464         ViewAsserts.assertVerticalCenterAligned(parent, leftView);
    465         ViewAsserts.assertVerticalCenterAligned(parent, centerView);
    466         ViewAsserts.assertVerticalCenterAligned(parent, rightView);
    467 
    468         final int parentHeight = parent.getHeight();
    469 
    470         int verticalOffset = (parentHeight - leftView.getHeight()) / 2;
    471         assertEquals(verticalOffset, leftView.getTop());
    472         assertEquals(verticalOffset + leftView.getHeight(), leftView.getBottom());
    473         assertEquals(originalLeftViewLeft, leftView.getLeft());
    474         assertEquals(originalLeftViewRight, leftView.getRight());
    475 
    476         verticalOffset = (parentHeight - centerView.getHeight()) / 2;
    477         assertEquals(verticalOffset, centerView.getTop());
    478         assertEquals(verticalOffset + centerView.getHeight(), centerView.getBottom());
    479         assertEquals(originalCenterViewLeft, centerView.getLeft());
    480         assertEquals(originalCenterViewRight, centerView.getRight());
    481 
    482         verticalOffset = (parentHeight - rightView.getHeight()) / 2;
    483         assertEquals(verticalOffset, rightView.getTop());
    484         assertEquals(verticalOffset + rightView.getHeight(), rightView.getBottom());
    485         assertEquals(originalRightViewLeft, rightView.getLeft());
    486         assertEquals(originalRightViewRight, rightView.getRight());
    487     }
    488 
    489     @Test
    490     public void testBottomGravityOnHorizontalLayout() throws Throwable {
    491         LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_weightsum);
    492         TextView leftView = (TextView) parent.findViewById(R.id.weight_0_2);
    493         TextView centerView = (TextView) parent.findViewById(R.id.weight_0_5);
    494         TextView rightView = (TextView) parent.findViewById(R.id.weight_0_3);
    495 
    496         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    497                 () -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
    498 
    499         int originalLeftViewLeft = leftView.getLeft();
    500         int originalLeftViewRight = leftView.getRight();
    501         int originalCenterViewLeft = centerView.getLeft();
    502         int originalCenterViewRight = centerView.getRight();
    503         int originalRightViewLeft = rightView.getLeft();
    504         int originalRightViewRight = rightView.getRight();
    505 
    506         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    507                 () -> parent.setVerticalGravity(Gravity.BOTTOM));
    508 
    509         assertEquals(Gravity.BOTTOM, parent.getGravity() & Gravity.VERTICAL_GRAVITY_MASK);
    510 
    511         ViewAsserts.assertBottomAligned(parent, leftView);
    512         ViewAsserts.assertBottomAligned(parent, centerView);
    513         ViewAsserts.assertBottomAligned(parent, rightView);
    514 
    515         final int parentHeight = parent.getHeight();
    516 
    517         assertEquals(parentHeight - leftView.getHeight(), leftView.getTop());
    518         assertEquals(parentHeight, leftView.getBottom());
    519         assertEquals(originalLeftViewLeft, leftView.getLeft());
    520         assertEquals(originalLeftViewRight, leftView.getRight());
    521 
    522         assertEquals(parentHeight - centerView.getHeight(), centerView.getTop());
    523         assertEquals(parentHeight, centerView.getBottom());
    524         assertEquals(originalCenterViewLeft, centerView.getLeft());
    525         assertEquals(originalCenterViewRight, centerView.getRight());
    526 
    527         assertEquals(parentHeight - rightView.getHeight(), rightView.getTop());
    528         assertEquals(parentHeight, rightView.getBottom());
    529         assertEquals(originalRightViewLeft, rightView.getLeft());
    530         assertEquals(originalRightViewRight, rightView.getRight());
    531     }
    532 
    533     @Test
    534     public void testHorizontalCenterGravityOnVerticalLayout() throws Throwable {
    535         LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_weightsum_vertical);
    536         TextView topView = (TextView) parent.findViewById(R.id.weight_0_1);
    537         TextView centerView = (TextView) parent.findViewById(R.id.weight_0_4);
    538         TextView bottomView = (TextView) parent.findViewById(R.id.weight_0_5);
    539 
    540         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    541                 () -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
    542 
    543         final int parentWidth = parent.getHeight();
    544 
    545         int originalTopViewTop = topView.getTop();
    546         int originalTopViewBottom = topView.getBottom();
    547         int originalCenterViewTop = centerView.getTop();
    548         int originalCenterViewBottom = centerView.getBottom();
    549         int originalBottomViewTop = bottomView.getTop();
    550         int originalBottomViewBottom = bottomView.getBottom();
    551 
    552         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    553                 () -> parent.setHorizontalGravity(Gravity.CENTER_HORIZONTAL));
    554 
    555         assertEquals(Gravity.CENTER_HORIZONTAL,
    556                 parent.getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK);
    557 
    558         ViewAsserts.assertHorizontalCenterAligned(parent, topView);
    559         ViewAsserts.assertHorizontalCenterAligned(parent, centerView);
    560         ViewAsserts.assertHorizontalCenterAligned(parent, bottomView);
    561 
    562         int horizontalOffset = (parentWidth - topView.getWidth()) / 2;
    563         assertEquals(originalTopViewTop, topView.getTop());
    564         assertEquals(originalTopViewBottom, topView.getBottom());
    565         assertEquals(horizontalOffset, topView.getLeft());
    566         assertEquals(horizontalOffset + topView.getWidth(), topView.getRight());
    567 
    568         horizontalOffset = (parentWidth - centerView.getWidth()) / 2;
    569         assertEquals(originalCenterViewTop, centerView.getTop());
    570         assertEquals(originalCenterViewBottom, centerView.getBottom());
    571         assertEquals(horizontalOffset, centerView.getLeft());
    572         assertEquals(horizontalOffset + centerView.getWidth(), centerView.getRight());
    573 
    574         horizontalOffset = (parentWidth - bottomView.getWidth()) / 2;
    575         assertEquals(originalBottomViewTop, bottomView.getTop());
    576         assertEquals(originalBottomViewBottom, bottomView.getBottom());
    577         assertEquals(horizontalOffset, bottomView.getLeft());
    578         assertEquals(horizontalOffset + bottomView.getWidth(), bottomView.getRight());
    579     }
    580 
    581     @Test
    582     public void testRightGravityOnVerticalLayout() throws Throwable {
    583         LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_weightsum_vertical);
    584         TextView topView = (TextView) parent.findViewById(R.id.weight_0_1);
    585         TextView centerView = (TextView) parent.findViewById(R.id.weight_0_4);
    586         TextView bottomView = (TextView) parent.findViewById(R.id.weight_0_5);
    587 
    588         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    589                 () -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
    590 
    591         final int parentWidth = parent.getHeight();
    592 
    593         int originalTopViewTop = topView.getTop();
    594         int originalTopViewBottom = topView.getBottom();
    595         int originalCenterViewTop = centerView.getTop();
    596         int originalCenterViewBottom = centerView.getBottom();
    597         int originalBottomViewTop = bottomView.getTop();
    598         int originalBottomViewBottom = bottomView.getBottom();
    599 
    600         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    601                 () -> parent.setHorizontalGravity(Gravity.RIGHT));
    602 
    603         assertEquals(Gravity.RIGHT, parent.getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK);
    604 
    605         ViewAsserts.assertRightAligned(parent, topView);
    606         ViewAsserts.assertRightAligned(parent, centerView);
    607         ViewAsserts.assertRightAligned(parent, bottomView);
    608 
    609         assertEquals(originalTopViewTop, topView.getTop());
    610         assertEquals(originalTopViewBottom, topView.getBottom());
    611         assertEquals(parentWidth - topView.getWidth(), topView.getLeft());
    612         assertEquals(parentWidth, topView.getRight());
    613 
    614         assertEquals(originalCenterViewTop, centerView.getTop());
    615         assertEquals(originalCenterViewBottom, centerView.getBottom());
    616         assertEquals(parentWidth - centerView.getWidth(), centerView.getLeft());
    617         assertEquals(parentWidth, centerView.getRight());
    618 
    619         assertEquals(originalBottomViewTop, bottomView.getTop());
    620         assertEquals(originalBottomViewBottom, bottomView.getBottom());
    621         assertEquals(parentWidth - bottomView.getWidth(), bottomView.getLeft());
    622         assertEquals(parentWidth, bottomView.getRight());
    623     }
    624 
    625     private void verifyBounds(final ViewGroup viewGroup, final View view,
    626             final CountDownLatch countDownLatch, final int left, final int top,
    627             final int width, final int height) {
    628         viewGroup.getViewTreeObserver().addOnPreDrawListener(
    629                 new ViewTreeObserver.OnPreDrawListener() {
    630                     @Override
    631                     public boolean onPreDraw() {
    632                         assertEquals(left, view.getLeft());
    633                         assertEquals(top, view.getTop());
    634                         assertEquals(width, view.getWidth());
    635                         assertEquals(height, view.getHeight());
    636                         countDownLatch.countDown();
    637                         viewGroup.getViewTreeObserver().removeOnPreDrawListener(this);
    638                         return true;
    639                     }
    640                 });
    641     }
    642 
    643     @Test
    644     public void testVisibilityAffectsLayout() throws Throwable {
    645         // Toggling view visibility between GONE/VISIBLE can affect the position of
    646         // other children in that container. This test verifies that these changes
    647         // on the first child of a LinearLayout affects the position of a second child
    648         final int childWidth = 100;
    649         final int childHeight = 200;
    650         final LinearLayout parent = new LinearLayout(mActivity);
    651         ViewGroup.LayoutParams parentParams = new ViewGroup.LayoutParams(
    652                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    653         parent.setLayoutParams(parentParams);
    654         final View child1 = new View(mActivity);
    655         child1.setBackgroundColor(Color.GREEN);
    656         ViewGroup.LayoutParams childParams = new ViewGroup.LayoutParams(childWidth, childHeight);
    657         child1.setLayoutParams(childParams);
    658         final View child2 = new View(mActivity);
    659         child2.setBackgroundColor(Color.RED);
    660         childParams = new ViewGroup.LayoutParams(childWidth, childHeight);
    661         child2.setLayoutParams(childParams);
    662         final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.linearlayout_root);
    663 
    664         final CountDownLatch countDownLatch1 = new CountDownLatch(1);
    665         mActivityRule.runOnUiThread(() -> {
    666             viewGroup.removeAllViews();
    667             viewGroup.addView(parent);
    668             parent.addView(child1);
    669             parent.addView(child2);
    670             verifyBounds(viewGroup, child1, countDownLatch1, 0, 0, childWidth, childHeight);
    671             verifyBounds(viewGroup, child2, countDownLatch1,
    672                     childWidth, 0, childWidth, childHeight);
    673         });
    674         try {
    675             assertTrue(countDownLatch1.await(500, TimeUnit.MILLISECONDS));
    676         } catch (InterruptedException ie) {
    677             fail(ie.getMessage());
    678         }
    679 
    680         final CountDownLatch countDownLatch2 = new CountDownLatch(1);
    681         mActivityRule.runOnUiThread(() -> {
    682             child1.setVisibility(View.GONE);
    683             verifyBounds(viewGroup, child2, countDownLatch2, 0, 0, childWidth, childHeight);
    684         });
    685         try {
    686             assertTrue(countDownLatch2.await(500, TimeUnit.MILLISECONDS));
    687         } catch (InterruptedException ie) {
    688             fail(ie.getMessage());
    689         }
    690 
    691         final CountDownLatch countDownLatch3 = new CountDownLatch(2);
    692         mActivityRule.runOnUiThread(() -> {
    693             child1.setVisibility(View.VISIBLE);
    694             verifyBounds(viewGroup, child1, countDownLatch3, 0, 0, childWidth, childHeight);
    695             verifyBounds(viewGroup, child2, countDownLatch3,
    696                     childWidth, 0, childWidth, childHeight);
    697         });
    698         try {
    699             assertTrue(countDownLatch3.await(500, TimeUnit.MILLISECONDS));
    700         } catch (InterruptedException ie) {
    701             fail(ie.getMessage());
    702         }
    703     }
    704 
    705     private void verifyVisualsOfVerticalLayoutWithDivider(LinearLayout parent,
    706             int expectedDividerPositionMask,
    707             int expectedDividerSize, @ColorInt int expectedDividerColor,
    708             int expectedDividerPadding) {
    709         final int parentWidth = parent.getWidth();
    710         final int parentHeight = parent.getHeight();
    711 
    712         final boolean expectingTopDivider =
    713                 (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_BEGINNING) != 0;
    714         final boolean expectingMiddleDivider =
    715                 (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_MIDDLE) != 0;
    716         final boolean expectingBottomDivider =
    717                 (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_END) != 0;
    718         final int expectedDividerCount = (expectingTopDivider ? 1 : 0)
    719                 + (expectingMiddleDivider ? 1 : 0) + (expectingBottomDivider ? 1 : 0);
    720 
    721         final int expectedChildHeight =
    722                 (parentHeight - expectedDividerCount * expectedDividerSize) / 2;
    723 
    724         final int expectedTopChildTop = expectingTopDivider ? expectedDividerSize : 0;
    725         TestUtils.assertRegionPixelsOfColor("Region of first child is blue", parent,
    726                 new Rect(0, expectedTopChildTop, parentWidth,
    727                         expectedTopChildTop + expectedChildHeight),
    728                 Color.BLUE, 1, true);
    729 
    730         final int expectedBottomChildBottom =
    731                 expectingBottomDivider ? parentHeight - expectedDividerSize : parentHeight;
    732         TestUtils.assertRegionPixelsOfColor("Region of second child is green", parent,
    733                 new Rect(0, expectedBottomChildBottom - expectedChildHeight, parentWidth,
    734                         expectedBottomChildBottom),
    735                 Color.GREEN, 1, true);
    736 
    737         if (expectedDividerSize == 0) {
    738             return;
    739         }
    740 
    741         // Do we expect top divider?
    742         if (expectingTopDivider) {
    743             TestUtils.assertRegionPixelsOfColor(
    744                     "Region of top divider is " + TestUtils.formatColorToHex(expectedDividerColor),
    745                     parent,
    746                     new Rect(expectedDividerPadding, 0, parentWidth - expectedDividerPadding,
    747                             expectedDividerSize),
    748                     expectedDividerColor, 1, true);
    749             TestUtils.assertRegionPixelsOfColor("Region of left padding of top divider is yellow",
    750                     parent,
    751                     new Rect(0, 0, expectedDividerPadding, expectedDividerSize),
    752                     Color.YELLOW, 1, true);
    753             TestUtils.assertRegionPixelsOfColor("Region of right padding of top divider is yellow",
    754                     parent,
    755                     new Rect(parentWidth - expectedDividerPadding, 0, parentWidth,
    756                             expectedDividerSize),
    757                     Color.YELLOW, 1, true);
    758         }
    759 
    760         // Do we expect middle divider?
    761         if (expectingMiddleDivider) {
    762             final int expectedMiddleDividerTop = expectedTopChildTop + expectedChildHeight;
    763             TestUtils.assertRegionPixelsOfColor(
    764                     "Region of middle divider is " +
    765                             TestUtils.formatColorToHex(expectedDividerColor),
    766                     parent,
    767                     new Rect(expectedDividerPadding, expectedMiddleDividerTop,
    768                             parentWidth - expectedDividerPadding,
    769                             expectedMiddleDividerTop + expectedDividerSize),
    770                     expectedDividerColor, 1, true);
    771             TestUtils.assertRegionPixelsOfColor(
    772                     "Region of left padding of middle divider is yellow",
    773                     parent,
    774                     new Rect(0, expectedMiddleDividerTop, expectedDividerPadding,
    775                             expectedMiddleDividerTop + expectedDividerSize),
    776                     Color.YELLOW, 1, true);
    777             TestUtils.assertRegionPixelsOfColor(
    778                     "Region of right padding of middle divider is yellow",
    779                     parent,
    780                     new Rect(parentWidth - expectedDividerPadding, expectedMiddleDividerTop,
    781                             parentWidth, expectedMiddleDividerTop + expectedDividerSize),
    782                     Color.YELLOW, 1, true);
    783         }
    784 
    785         // Do we expect bottom divider?
    786         if (expectingBottomDivider) {
    787             final int expectedBottomDividerTop = expectedBottomChildBottom;
    788             TestUtils.assertRegionPixelsOfColor(
    789                     "Region of bottom divider is " +
    790                             TestUtils.formatColorToHex(expectedDividerColor),
    791                     parent,
    792                     new Rect(expectedDividerPadding, expectedBottomDividerTop,
    793                             parentWidth - expectedDividerPadding,
    794                             expectedBottomDividerTop + expectedDividerSize),
    795                     expectedDividerColor, 1, true);
    796             TestUtils.assertRegionPixelsOfColor(
    797                     "Region of left padding of bottom divider is yellow",
    798                     parent,
    799                     new Rect(0, expectedBottomDividerTop, expectedDividerPadding,
    800                             expectedBottomDividerTop + expectedDividerSize),
    801                     Color.YELLOW, 1, true);
    802             TestUtils.assertRegionPixelsOfColor(
    803                     "Region of right padding of bottom divider is yellow",
    804                     parent,
    805                     new Rect(parentWidth - expectedDividerPadding, expectedBottomDividerTop,
    806                             parentWidth, expectedBottomDividerTop + expectedDividerSize),
    807                     Color.YELLOW, 1, true);
    808         }
    809     }
    810 
    811     /**
    812      * layout of vertical LinearLayout.
    813      * -----------------------------------
    814      * | ------------------------------- |
    815      * | |            child1           | |
    816      * | ------------------------------- |
    817      * | - - - - - - divider - - - - - - |
    818      * | ------------------------------- |
    819      * | |            child2           | |
    820      * | ------------------------------- |
    821      * -----------------------------------
    822      *
    823      * Parent is filled with yellow color. Child 1 is filled with green and child 2 is filled
    824      * with blue. Divider is red at the beginning. Throughout this method we reconfigure the
    825      * visibility, drawable and paddings of the divider and verify the overall visuals of the
    826      * container.
    827      */
    828     @Test
    829     public void testDividersInVerticalLayout() throws Throwable {
    830         final LinearLayout parent =
    831                 (LinearLayout) mActivity.findViewById(R.id.linear_vertical_with_divider);
    832 
    833         final Resources res = mActivity.getResources();
    834         final int dividerSize = res.getDimensionPixelSize(R.dimen.linear_layout_divider_size);
    835         final int dividerPadding = res.getDimensionPixelSize(R.dimen.linear_layout_divider_padding);
    836 
    837         assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE, parent.getShowDividers());
    838         assertEquals(dividerPadding, parent.getDividerPadding());
    839         final Drawable dividerDrawable = parent.getDividerDrawable();
    840         TestUtils.assertAllPixelsOfColor("Divider is red", dividerDrawable,
    841                 dividerDrawable.getIntrinsicWidth(), dividerDrawable.getIntrinsicHeight(),
    842                 false, Color.RED, 1, true);
    843 
    844         // Test the initial visuals of the entire parent
    845         verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
    846                 dividerSize, Color.RED, dividerPadding);
    847 
    848         // Change the divider to magenta
    849         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    850                 () -> parent.setDividerDrawable(
    851                         mActivity.getDrawable(R.drawable.linear_layout_divider_magenta)));
    852         verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
    853                 dividerSize, Color.MAGENTA, dividerPadding);
    854 
    855         // Change the divider to null (no divider effectively)
    856         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    857                 () -> parent.setDividerDrawable(null));
    858         verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
    859                 0, Color.TRANSPARENT, 0);
    860 
    861         // Change the divider back to red
    862         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    863                 () -> parent.setDividerDrawable(
    864                         mActivity.getDrawable(R.drawable.linear_layout_divider_red)));
    865         verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
    866                 dividerSize, Color.RED, dividerPadding);
    867 
    868         // Change the padding to half the original size
    869         final int halfPadding = dividerPadding / 2;
    870         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    871                 () -> parent.setDividerPadding(halfPadding));
    872         assertEquals(halfPadding, parent.getDividerPadding());
    873         verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
    874                 dividerSize, Color.RED, halfPadding);
    875 
    876         // Change the padding to twice the original size
    877         final int doublePadding = dividerPadding * 2;
    878         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    879                 () -> parent.setDividerPadding(doublePadding));
    880         assertEquals(doublePadding, parent.getDividerPadding());
    881         verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
    882                 dividerSize, Color.RED, doublePadding);
    883 
    884         // And back to the original padding
    885         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    886                 () -> parent.setDividerPadding(dividerPadding));
    887         assertEquals(dividerPadding, parent.getDividerPadding());
    888         verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
    889                 dividerSize, Color.RED, dividerPadding);
    890 
    891         // Set show dividers to NONE (no divider effectively)
    892         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    893                 () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_NONE));
    894         assertEquals(LinearLayout.SHOW_DIVIDER_NONE, parent.getShowDividers());
    895         verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_NONE,
    896                 0, Color.TRANSPARENT, 0);
    897 
    898         // Show only top divider
    899         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    900                 () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_BEGINNING));
    901         assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING, parent.getShowDividers());
    902         verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_BEGINNING,
    903                 dividerSize, Color.RED, dividerPadding);
    904 
    905         // Show only bottom divider
    906         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    907                 () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_END));
    908         assertEquals(LinearLayout.SHOW_DIVIDER_END, parent.getShowDividers());
    909         verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_END,
    910                 dividerSize, Color.RED, dividerPadding);
    911 
    912         // Show top and bottom dividers
    913         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    914                 () -> parent.setShowDividers(
    915                         LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END));
    916         assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END,
    917                 parent.getShowDividers());
    918         verifyVisualsOfVerticalLayoutWithDivider(parent,
    919                 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END,
    920                 dividerSize, Color.RED, dividerPadding);
    921 
    922         // Show top and middle dividers
    923         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    924                 () -> parent.setShowDividers(
    925                         LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE));
    926         assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE,
    927                 parent.getShowDividers());
    928         verifyVisualsOfVerticalLayoutWithDivider(parent,
    929                 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE,
    930                 dividerSize, Color.RED, dividerPadding);
    931 
    932         // Show middle and bottom dividers
    933         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    934                 () -> parent.setShowDividers(
    935                         LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END));
    936         assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END,
    937                 parent.getShowDividers());
    938         verifyVisualsOfVerticalLayoutWithDivider(parent,
    939                 LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END,
    940                 dividerSize, Color.RED, dividerPadding);
    941 
    942         // Show top, middle and bottom dividers
    943         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
    944                 () -> parent.setShowDividers(
    945                         LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
    946                                 | LinearLayout.SHOW_DIVIDER_END));
    947         assertEquals(
    948                 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
    949                         | LinearLayout.SHOW_DIVIDER_END,
    950                 parent.getShowDividers());
    951         verifyVisualsOfVerticalLayoutWithDivider(parent,
    952                 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
    953                         | LinearLayout.SHOW_DIVIDER_END,
    954                 dividerSize, Color.RED, dividerPadding);
    955     }
    956 
    957     private void verifyVisualsOfHorizontalLayoutWithDivider(LinearLayout parent,
    958             int expectedDividerPositionMask,
    959             int expectedDividerSize, @ColorInt int expectedDividerColor,
    960             int expectedDividerPadding) {
    961         final int parentWidth = parent.getWidth();
    962         final int parentHeight = parent.getHeight();
    963 
    964         final boolean expectingLeftDivider =
    965                 (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_BEGINNING) != 0;
    966         final boolean expectingMiddleDivider =
    967                 (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_MIDDLE) != 0;
    968         final boolean expectingRightDivider =
    969                 (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_END) != 0;
    970         final int expectedDividerCount = (expectingLeftDivider ? 1 : 0)
    971                 + (expectingMiddleDivider ? 1 : 0) + (expectingRightDivider ? 1 : 0);
    972 
    973         final int expectedChildWidth =
    974                 (parentWidth - expectedDividerCount * expectedDividerSize) / 2;
    975 
    976         final int expectedLeftChildLeft = expectingLeftDivider ? expectedDividerSize : 0;
    977         TestUtils.assertRegionPixelsOfColor("Region of first child is blue", parent,
    978                 new Rect(expectedLeftChildLeft, 0,
    979                         expectedLeftChildLeft + expectedChildWidth, parentHeight),
    980                 Color.BLUE, 1, true);
    981 
    982         final int expectedRightChildRight =
    983                 expectingRightDivider ? parentWidth - expectedDividerSize : parentWidth;
    984         TestUtils.assertRegionPixelsOfColor("Region of second child is green", parent,
    985                 new Rect(expectedRightChildRight - expectedChildWidth, 0, expectedRightChildRight,
    986                         parentHeight),
    987                 Color.GREEN, 1, true);
    988 
    989         if (expectedDividerSize == 0) {
    990             return;
    991         }
    992 
    993         // Do we expect left divider?
    994         if (expectingLeftDivider) {
    995             TestUtils.assertRegionPixelsOfColor(
    996                     "Region of left divider is " + TestUtils.formatColorToHex(expectedDividerColor),
    997                     parent,
    998                     new Rect(0, expectedDividerPadding, expectedDividerSize,
    999                             parentHeight - expectedDividerPadding),
   1000                     expectedDividerColor, 1, true);
   1001             TestUtils.assertRegionPixelsOfColor(
   1002                     "Region of top padding of left divider is yellow",
   1003                     parent,
   1004                     new Rect(0, 0, expectedDividerSize, expectedDividerPadding),
   1005                     Color.YELLOW, 1, true);
   1006             TestUtils.assertRegionPixelsOfColor(
   1007                     "Region of bottom padding of left divider is yellow",
   1008                     parent,
   1009                     new Rect(0, parentHeight - expectedDividerPadding, expectedDividerSize,
   1010                             parentHeight),
   1011                     Color.YELLOW, 1, true);
   1012         }
   1013 
   1014         // Do we expect middle divider?
   1015         if (expectingMiddleDivider) {
   1016             final int expectedMiddleDividerLeft = expectedLeftChildLeft + expectedChildWidth;
   1017             TestUtils.assertRegionPixelsOfColor(
   1018                     "Region of middle divider is " +
   1019                             TestUtils.formatColorToHex(expectedDividerColor),
   1020                     parent,
   1021                     new Rect(expectedMiddleDividerLeft, expectedDividerPadding,
   1022                             expectedMiddleDividerLeft + expectedDividerSize,
   1023                             parentHeight - expectedDividerPadding),
   1024                     expectedDividerColor, 1, true);
   1025             TestUtils.assertRegionPixelsOfColor(
   1026                     "Region of top padding of middle divider is yellow",
   1027                     parent,
   1028                     new Rect(expectedMiddleDividerLeft, 0,
   1029                             expectedMiddleDividerLeft + expectedDividerSize,
   1030                             expectedDividerPadding),
   1031                     Color.YELLOW, 1, true);
   1032             TestUtils.assertRegionPixelsOfColor(
   1033                     "Region of bottom padding of middle divider is yellow",
   1034                     parent,
   1035                     new Rect(expectedMiddleDividerLeft, parentHeight - expectedDividerPadding,
   1036                             expectedMiddleDividerLeft + expectedDividerSize, parentHeight),
   1037                     Color.YELLOW, 1, true);
   1038         }
   1039 
   1040         // Do we expect right divider?
   1041         if (expectingRightDivider) {
   1042             final int expectedRightDividerLeft = expectedRightChildRight;
   1043             TestUtils.assertRegionPixelsOfColor(
   1044                     "Region of right divider is " +
   1045                             TestUtils.formatColorToHex(expectedDividerColor),
   1046                     parent,
   1047                     new Rect(expectedRightDividerLeft, expectedDividerPadding,
   1048                             expectedRightDividerLeft + expectedDividerSize,
   1049                             parentHeight - expectedDividerPadding),
   1050                     expectedDividerColor, 1, true);
   1051             TestUtils.assertRegionPixelsOfColor(
   1052                     "Region of top padding of right divider is yellow",
   1053                     parent,
   1054                     new Rect(expectedRightDividerLeft, 0,
   1055                             expectedRightDividerLeft + expectedDividerSize,
   1056                             expectedDividerPadding),
   1057                     Color.YELLOW, 1, true);
   1058             TestUtils.assertRegionPixelsOfColor(
   1059                     "Region of bottom padding of right divider is yellow",
   1060                     parent,
   1061                     new Rect(expectedRightDividerLeft, parentHeight - expectedDividerPadding,
   1062                             expectedRightDividerLeft + expectedDividerSize, parentHeight),
   1063                     Color.YELLOW, 1, true);
   1064         }
   1065     }
   1066 
   1067     /**
   1068      * layout of horizontal LinearLayout.
   1069      * -----------------------------------
   1070      * | ------------  |  -------------  |
   1071      * | |          |     |           |  |
   1072      * | |          |  d  |           |  |
   1073      * | |          |  i  |           |  |
   1074      * | |          |  v  |           |  |
   1075      * | |  child1  |  i  |  child2   |  |
   1076      * | |          |  d  |           |  |
   1077      * | |          |  e  |           |  |
   1078      * | |          |  r  |           |  |
   1079      * | |          |     |           |  |
   1080      * | ------------  |  -------------  |
   1081      * -----------------------------------
   1082      *
   1083      * Parent is filled with yellow color. Child 1 is filled with green and child 2 is filled
   1084      * with blue. Divider is red at the beginning. Throughout this method we reconfigure the
   1085      * visibility, drawable and paddings of the divider and verify the overall visuals of the
   1086      * container.
   1087      */
   1088     @Test
   1089     public void testDividersInHorizontalLayout() throws Throwable {
   1090         final LinearLayout parent =
   1091                 (LinearLayout) mActivity.findViewById(R.id.linear_horizontal_with_divider);
   1092 
   1093         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
   1094                 () -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
   1095 
   1096         final Resources res = mActivity.getResources();
   1097         final int dividerSize = res.getDimensionPixelSize(R.dimen.linear_layout_divider_size);
   1098         final int dividerPadding = res.getDimensionPixelSize(R.dimen.linear_layout_divider_padding);
   1099 
   1100         assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE, parent.getShowDividers());
   1101         assertEquals(dividerPadding, parent.getDividerPadding());
   1102         final Drawable dividerDrawable = parent.getDividerDrawable();
   1103         TestUtils.assertAllPixelsOfColor("Divider is red", dividerDrawable,
   1104                 dividerDrawable.getIntrinsicWidth(), dividerDrawable.getIntrinsicHeight(),
   1105                 false, Color.RED, 1, true);
   1106 
   1107         // Test the initial visuals of the entire parent
   1108         verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
   1109                 dividerSize, Color.RED, dividerPadding);
   1110 
   1111         // Change the divider to magenta
   1112         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
   1113                 () -> parent.setDividerDrawable(
   1114                         mActivity.getDrawable(R.drawable.linear_layout_divider_magenta)));
   1115         verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
   1116                 dividerSize, Color.MAGENTA, dividerPadding);
   1117 
   1118         // Change the divider to null (no divider effectively)
   1119         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
   1120                 () -> parent.setDividerDrawable(null));
   1121         verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
   1122                 0, Color.TRANSPARENT, 0);
   1123 
   1124         // Change the divider back to red
   1125         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
   1126                 () -> parent.setDividerDrawable(
   1127                         mActivity.getDrawable(R.drawable.linear_layout_divider_red)));
   1128         verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
   1129                 dividerSize, Color.RED, dividerPadding);
   1130 
   1131         // Change the padding to half the original size
   1132         final int halfPadding = dividerPadding / 2;
   1133         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
   1134                 () -> parent.setDividerPadding(halfPadding));
   1135         assertEquals(halfPadding, parent.getDividerPadding());
   1136         verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
   1137                 dividerSize, Color.RED, halfPadding);
   1138 
   1139         // Change the padding to twice the original size
   1140         final int doublePadding = dividerPadding * 2;
   1141         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
   1142                 () -> parent.setDividerPadding(doublePadding));
   1143         assertEquals(doublePadding, parent.getDividerPadding());
   1144         verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
   1145                 dividerSize, Color.RED, doublePadding);
   1146 
   1147         // And back to the original padding
   1148         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
   1149                 () -> parent.setDividerPadding(dividerPadding));
   1150         assertEquals(dividerPadding, parent.getDividerPadding());
   1151         verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
   1152                 dividerSize, Color.RED, dividerPadding);
   1153 
   1154         // Set show dividers to NONE (no divider effectively)
   1155         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
   1156                 () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_NONE));
   1157         assertEquals(LinearLayout.SHOW_DIVIDER_NONE, parent.getShowDividers());
   1158         verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_NONE,
   1159                 0, Color.TRANSPARENT, 0);
   1160 
   1161         // Show only left divider
   1162         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
   1163                 () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_BEGINNING));
   1164         assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING, parent.getShowDividers());
   1165         verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_BEGINNING,
   1166                 dividerSize, Color.RED, dividerPadding);
   1167 
   1168         // Show only right divider
   1169         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
   1170                 () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_END));
   1171         assertEquals(LinearLayout.SHOW_DIVIDER_END, parent.getShowDividers());
   1172         verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_END,
   1173                 dividerSize, Color.RED, dividerPadding);
   1174 
   1175         // Show left and right dividers
   1176         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
   1177                 () -> parent.setShowDividers(
   1178                         LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END));
   1179         assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END,
   1180                 parent.getShowDividers());
   1181         verifyVisualsOfHorizontalLayoutWithDivider(parent,
   1182                 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END,
   1183                 dividerSize, Color.RED, dividerPadding);
   1184 
   1185         // Show left and middle dividers
   1186         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
   1187                 () -> parent.setShowDividers(
   1188                         LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE));
   1189         assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE,
   1190                 parent.getShowDividers());
   1191         verifyVisualsOfHorizontalLayoutWithDivider(parent,
   1192                 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE,
   1193                 dividerSize, Color.RED, dividerPadding);
   1194 
   1195         // Show middle and right dividers
   1196         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
   1197                 () -> parent.setShowDividers(
   1198                         LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END));
   1199         assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END,
   1200                 parent.getShowDividers());
   1201         verifyVisualsOfHorizontalLayoutWithDivider(parent,
   1202                 LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END,
   1203                 dividerSize, Color.RED, dividerPadding);
   1204 
   1205         // Show left, middle and right dividers
   1206         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
   1207                 () -> parent.setShowDividers(
   1208                         LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
   1209                                 | LinearLayout.SHOW_DIVIDER_END));
   1210         assertEquals(
   1211                 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
   1212                         | LinearLayout.SHOW_DIVIDER_END,
   1213                 parent.getShowDividers());
   1214         verifyVisualsOfHorizontalLayoutWithDivider(parent,
   1215                 LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
   1216                         | LinearLayout.SHOW_DIVIDER_END,
   1217                 dividerSize, Color.RED, dividerPadding);
   1218     }
   1219 
   1220     @Test
   1221     public void testZeroWeightDistributionHorizontal() throws Throwable {
   1222         // Ensure that weight is correctly distributed when there is no excess space.
   1223         final View content = mActivity.findViewById(android.R.id.content);
   1224         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, content,
   1225                 () -> mActivity.setContentView(R.layout.linearlayout_zero_weight_horizontal));
   1226 
   1227         final View parent = mActivity.findViewById(R.id.container1);
   1228         assertEquals(0, mActivity.findViewById(R.id.view1).getWidth());
   1229         assertEquals(0, mActivity.findViewById(R.id.view2).getWidth());
   1230         assertEquals(parent.getWidth(), mActivity.findViewById(R.id.view3).getWidth());
   1231     }
   1232 
   1233     @Test
   1234     public void testZeroWeightDistributionVertical() throws Throwable {
   1235         // Ensure that weight is correctly distributed when there is no excess space.
   1236         final View content = mActivity.findViewById(android.R.id.content);
   1237         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, content,
   1238                 () -> mActivity.setContentView(R.layout.linearlayout_zero_weight_vertical));
   1239 
   1240         final View parent = mActivity.findViewById(R.id.container1);
   1241         assertEquals(0, mActivity.findViewById(R.id.view1).getHeight());
   1242         assertEquals(0, mActivity.findViewById(R.id.view2).getHeight());
   1243         assertEquals(parent.getHeight(), mActivity.findViewById(R.id.view3).getHeight());
   1244     }
   1245 
   1246     private class MockListView extends ListView {
   1247         private final static int DEFAULT_CHILD_BASE_LINE = 1;
   1248 
   1249         public MockListView(Context context) {
   1250             super(context);
   1251         }
   1252 
   1253         public int getBaseline() {
   1254             return DEFAULT_CHILD_BASE_LINE;
   1255         }
   1256     }
   1257 
   1258     /**
   1259      * Add MockLinearLayout to help for testing protected methods in LinearLayout.
   1260      * Because we can not access protected methods in LinearLayout directly, we have to
   1261      * extends from it and override protected methods so that we can access them in
   1262      * our test codes.
   1263      */
   1264     public static class MockLinearLayout extends LinearLayout {
   1265         public MockLinearLayout(Context c) {
   1266             super(c);
   1267         }
   1268 
   1269         public MockLinearLayout(Context context, @Nullable AttributeSet attrs) {
   1270             super(context, attrs);
   1271         }
   1272 
   1273         @Override
   1274         protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
   1275             return super.checkLayoutParams(p);
   1276         }
   1277 
   1278         @Override
   1279         protected LinearLayout.LayoutParams generateDefaultLayoutParams() {
   1280             return super.generateDefaultLayoutParams();
   1281         }
   1282 
   1283         @Override
   1284         protected LinearLayout.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
   1285             return super.generateLayoutParams(p);
   1286         }
   1287     }
   1288 }
   1289