OSDN Git Service

Don't allow children of a SizeAdaptiveLayout to measure outside their declared range...
authorChris Wren <cwren@android.com>
Tue, 24 Apr 2012 13:50:03 +0000 (09:50 -0400)
committerChris Wren <cwren@android.com>
Tue, 24 Apr 2012 20:14:31 +0000 (16:14 -0400)
Bug: 6377749
Change-Id: Ie706006eee9c0ed8dda468212a652941b8e20be0

core/java/com/android/internal/widget/SizeAdaptiveLayout.java
core/tests/coretests/res/layout/size_adaptive_lies.xml [new file with mode: 0644]
core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java

index 0a99f17..bbf5509 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.android.internal.widget;
 
+import java.lang.Math;
+
 import com.android.internal.R;
 
 import android.animation.Animator;
@@ -157,9 +159,29 @@ public class SizeAdaptiveLayout extends ViewGroup {
         int childState = combineMeasuredStates(0, model.getMeasuredState());
         if (DEBUG) Log.d(TAG, "measured child at: " + childHeight);
         int resolvedWidth = resolveSizeAndState(childWidth, widthMeasureSpec, childState);
-        int resolvedheight = resolveSizeAndState(childHeight, heightMeasureSpec, childState);
-        setMeasuredDimension(resolvedWidth, resolvedheight);
-        if (DEBUG) Log.d(TAG, "resolved to: " + resolvedheight);
+        int resolvedHeight = resolveSizeAndState(childHeight, heightMeasureSpec, childState);
+        if (DEBUG) Log.d(TAG, "resolved to: " + resolvedHeight);
+        int boundedHeight = clampSizeToBounds(resolvedHeight, model);
+        if (DEBUG) Log.d(TAG, "bounded to: " + boundedHeight);
+        setMeasuredDimension(resolvedWidth, boundedHeight);
+    }
+
+    private int clampSizeToBounds(int measuredHeight, View child) {
+        SizeAdaptiveLayout.LayoutParams lp =
+                (SizeAdaptiveLayout.LayoutParams) child.getLayoutParams();
+        int heightIn = View.MEASURED_SIZE_MASK & measuredHeight;
+        int height = Math.max(heightIn, lp.minHeight);
+        if (lp.maxHeight != SizeAdaptiveLayout.LayoutParams.UNBOUNDED) {
+            height = Math.min(height, lp.maxHeight);
+        }
+
+        if (heightIn != height) {
+            Log.d(TAG, this + "child view " + child + " " +
+                  "measured out of bounds at " + heightIn +"px " +
+                  "clamped to " + height + "px");
+        }
+
+        return height;
     }
 
     //TODO extend to width and height
diff --git a/core/tests/coretests/res/layout/size_adaptive_lies.xml b/core/tests/coretests/res/layout/size_adaptive_lies.xml
new file mode 100644 (file)
index 0000000..7de892e
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/multi1"
+    android:layout_width="match_parent"
+    android:layout_height="64dp" >
+
+    <include
+        android:id="@+id/one_u"
+        layout="@layout/size_adaptive_one_u"
+        android:layout_width="fill_parent"
+        android:layout_height="64dp"
+        internal:layout_minHeight="64dp"
+        internal:layout_maxHeight="64dp"
+        />
+
+    <include
+        android:id="@+id/four_u"
+        layout="@layout/size_adaptive_one_u"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        internal:layout_minHeight="65dp"
+        internal:layout_maxHeight="unbounded"/>
+
+</com.android.internal.widget.SizeAdaptiveLayout>
index a937f65..efd06bf 100644 (file)
@@ -449,10 +449,42 @@ public class SizeAdaptiveLayoutTest extends AndroidTestCase {
                    panel.getBackground() instanceof ColorDrawable);
     }
 
+    @SmallTest
+    public void testOpenSmallEvenWhenLargeIsActuallySmall() {
+        inflate(R.layout.size_adaptive_lies);
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+        int height = (int) lp.minHeight;
+
+        measureAndLayout(height);
+
+        assertEquals("1U should be visible",
+                View.VISIBLE,
+                mSmallView.getVisibility());
+        assertTrue("1U should also have been measured",
+                   mSmallView.getMeasuredHeight() > 0);
+    }
+
+    @SmallTest
+    public void testOpenLargeEvenWhenLargeIsActuallySmall() {
+        inflate(R.layout.size_adaptive_lies);
+        SizeAdaptiveLayout.LayoutParams lp =
+          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+        int height = (int) lp.minHeight;
+
+        measureAndLayout(height);
+
+        assertEquals("4U should be visible",
+                View.VISIBLE,
+                mLargeView.getVisibility());
+        assertTrue("4U should also have been measured",
+                   mLargeView.getMeasuredHeight() > 0);
+    }
+
     private void measureAndLayout(int height) {
         // manually measure it, and lay it out
         int measureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
         mSizeAdaptiveLayout.measure(500, measureSpec);
-        mSizeAdaptiveLayout.layout(0, 0, 500, height);
+        mSizeAdaptiveLayout.layout(0, 0, 500, mSizeAdaptiveLayout.getMeasuredHeight());
     }
 }