Add test for toggling view visibility affecting layout

Toggling the visibility between GONE and VISIBILITY may affect
other children in that parent layout.

Issue #25980198 requestLayout() sometimes doesn't result in measure/layout for view

Change-Id: I826dbfe8018c19d50a033380c6748345bfdcd21d
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 355850f..314bd2a 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -2266,13 +2266,16 @@
         assertTrue(listener.hasOnClick());
     }
 
-    private void checkValues(final ViewGroup viewGroup, final ViewGroup parent,
-            final CountDownLatch countDownLatch, final int width, final int height) {
+    private void checkBounds(final ViewGroup viewGroup, final View view,
+            final CountDownLatch countDownLatch, final int left, final int top,
+            final int width, final int height) {
         viewGroup.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
             @Override
             public boolean onPreDraw() {
-                assertEquals(width, parent.getWidth());
-                assertEquals(height, parent.getHeight());
+                assertEquals(left, view.getLeft());
+                assertEquals(top, view.getTop());
+                assertEquals(width, view.getWidth());
+                assertEquals(height, view.getHeight());
                 countDownLatch.countDown();
                 viewGroup.getViewTreeObserver().removeOnPreDrawListener(this);
                 return true;
@@ -2304,7 +2307,7 @@
             public void run() {
                 viewGroup.removeAllViews();
                 viewGroup.addView(parent);
-                checkValues(viewGroup, parent, countDownLatch1, 0, parentHeight);
+                checkBounds(viewGroup, parent, countDownLatch1, 0, 0, 0, parentHeight);
             }
         });
         countDownLatch1.await(500, TimeUnit.MILLISECONDS);
@@ -2313,7 +2316,7 @@
         runTestOnUiThread(new Runnable() {
             public void run() {
                 parent.addView(child);
-                checkValues(viewGroup, parent, countDownLatch2, childWidth, parentHeight);
+                checkBounds(viewGroup, parent, countDownLatch2, 0, 0, childWidth, parentHeight);
             }
         });
         countDownLatch2.await(500, TimeUnit.MILLISECONDS);
@@ -2322,7 +2325,7 @@
         runTestOnUiThread(new Runnable() {
             public void run() {
                 parent.removeView(child);
-                checkValues(viewGroup, parent, countDownLatch3, 0, parentHeight);
+                checkBounds(viewGroup, parent, countDownLatch3, 0, 0, 0, parentHeight);
             }
         });
         countDownLatch3.await(500, TimeUnit.MILLISECONDS);
diff --git a/tests/tests/widget/res/layout/linearlayout_layout.xml b/tests/tests/widget/res/layout/linearlayout_layout.xml
index c70937d..8881552 100644
--- a/tests/tests/widget/res/layout/linearlayout_layout.xml
+++ b/tests/tests/widget/res/layout/linearlayout_layout.xml
@@ -15,6 +15,7 @@
  * limitations under the License.
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:id="@+id/linearlayout_root"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:orientation="vertical">
diff --git a/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java b/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
index 78a8eee..76fa782 100644
--- a/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
@@ -16,6 +16,9 @@
 
 package android.widget.cts;
 
+import android.graphics.Color;
+import android.view.View;
+import android.view.ViewTreeObserver;
 import org.xmlpull.v1.XmlPullParser;
 
 import android.app.Activity;
@@ -33,6 +36,9 @@
 
 import android.widget.cts.R;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Test {@link LinearLayout}.
  */
@@ -327,6 +333,78 @@
         assertEquals(parent.getWidth(), rightView.getRight());
     }
 
+    private void checkBounds(final ViewGroup viewGroup, final View view,
+            final CountDownLatch countDownLatch, final int left, final int top,
+            final int width, final int height) {
+        viewGroup.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+            @Override
+            public boolean onPreDraw() {
+                assertEquals(left, view.getLeft());
+                assertEquals(top, view.getTop());
+                assertEquals(width, view.getWidth());
+                assertEquals(height, view.getHeight());
+                countDownLatch.countDown();
+                viewGroup.getViewTreeObserver().removeOnPreDrawListener(this);
+                return true;
+            }
+        });
+    }
+
+    public void testVisibilityAffectsLayout() throws Throwable {
+        // Toggling view visibility between GONE/VISIBLE can affect the position of
+        // other children in that container. This test verifies that these changes
+        // on the first child of a LinearLayout affects the position of a second child
+        final int childWidth = 100;
+        final int childHeight = 200;
+        final LinearLayout parent = new LinearLayout(mActivity);
+        ViewGroup.LayoutParams parentParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+        parent.setLayoutParams(parentParams);
+        final View child1 = new View(mActivity);
+        child1.setBackgroundColor(Color.GREEN);
+        ViewGroup.LayoutParams childParams = new ViewGroup.LayoutParams(childWidth, childHeight);
+        child1.setLayoutParams(childParams);
+        final View child2 = new View(mActivity);
+        child2.setBackgroundColor(Color.RED);
+        childParams = new ViewGroup.LayoutParams(childWidth, childHeight);
+        child2.setLayoutParams(childParams);
+        final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.linearlayout_root);
+
+        final CountDownLatch countDownLatch1 = new CountDownLatch(1);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                viewGroup.removeAllViews();
+                viewGroup.addView(parent);
+                parent.addView(child1);
+                parent.addView(child2);
+                checkBounds(viewGroup, child1, countDownLatch1, 0, 0, childWidth, childHeight);
+                checkBounds(viewGroup, child2, countDownLatch1,
+                        childWidth, 0, childWidth, childHeight);
+            }
+        });
+        countDownLatch1.await(500, TimeUnit.MILLISECONDS);
+
+        final CountDownLatch countDownLatch2 = new CountDownLatch(1);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                child1.setVisibility(View.GONE);
+                checkBounds(viewGroup, child2, countDownLatch2, 0, 0, childWidth, childHeight);
+            }
+        });
+        countDownLatch2.await(500, TimeUnit.MILLISECONDS);
+
+        final CountDownLatch countDownLatch3 = new CountDownLatch(2);
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                child1.setVisibility(View.VISIBLE);
+                checkBounds(viewGroup, child1, countDownLatch3, 0, 0, childWidth, childHeight);
+                checkBounds(viewGroup, child2, countDownLatch3,
+                        childWidth, 0, childWidth, childHeight);
+            }
+        });
+        countDownLatch3.await(500, TimeUnit.MILLISECONDS);
+    }
+
     private class MockListView extends ListView {
         private final static int DEFAULT_CHILD_BASE_LINE = 1;