Implement smarter sizing of WRAP_CONTENT windows.

This extends the view hierarchy's measure pass to allow view to
propagate up to their parent additional information besides just
their measured size.  They can now report that their measured width
and/or height should be larger than the size their parent is
limiting them to (even though by definition they need to contrain
their reported measurements to the limits imposed by the parent).

ViewRoot uses this information to determine if it should remeasure
the window with a larger size limit to try to make it fit.

Change-Id: I90af3b7a8ec45d0a5c003fb009857025209d83eb
diff --git a/api/current.xml b/api/current.xml
index 7d7bec1..8af429d 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -205490,6 +205490,21 @@
  visibility="public"
 >
 </method>
+<method name="combineMeasuredStates"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="curState" type="int">
+</parameter>
+<parameter name="newState" type="int">
+</parameter>
+</method>
 <method name="computeHorizontalScrollExtent"
  return="int"
  abstract="false"
@@ -206417,6 +206432,28 @@
  visibility="public"
 >
 </method>
+<method name="getMeasuredHeightAndState"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMeasuredState"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getMeasuredWidth"
  return="int"
  abstract="false"
@@ -206428,6 +206465,17 @@
  visibility="public"
 >
 </method>
+<method name="getMeasuredWidthAndState"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getNextFocusDownId"
  return="int"
  abstract="false"
@@ -208333,6 +208381,23 @@
 <parameter name="measureSpec" type="int">
 </parameter>
 </method>
+<method name="resolveSizeAndState"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="size" type="int">
+</parameter>
+<parameter name="measureSpec" type="int">
+</parameter>
+<parameter name="childMeasuredState" type="int">
+</parameter>
+</method>
 <method name="restoreHierarchyState"
  return="void"
  abstract="false"
@@ -209792,6 +209857,50 @@
  visibility="public"
 >
 </field>
+<field name="MEASURED_HEIGHT_STATE_SHIFT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MEASURED_SIZE_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16777215"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MEASURED_STATE_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-16777216"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MEASURED_STATE_TOO_SMALL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16777216"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="NO_ID"
  type="int"
  transient="false"
diff --git a/core/java/android/app/FragmentBreadCrumbs.java b/core/java/android/app/FragmentBreadCrumbs.java
index e924c1c..139095f 100644
--- a/core/java/android/app/FragmentBreadCrumbs.java
+++ b/core/java/android/app/FragmentBreadCrumbs.java
@@ -110,6 +110,7 @@
 
         int maxHeight = 0;
         int maxWidth = 0;
+        int measuredChildState = 0;
 
         // Find rightmost and bottom-most child
         for (int i = 0; i < count; i++) {
@@ -118,6 +119,8 @@
                 measureChild(child, widthMeasureSpec, heightMeasureSpec);
                 maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
                 maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
+                measuredChildState = combineMeasuredStates(measuredChildState,
+                        child.getMeasuredState());
             }
         }
 
@@ -129,8 +132,9 @@
         maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
         maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
 
-        setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec),
-                resolveSize(maxHeight, heightMeasureSpec));
+        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, measuredChildState),
+                resolveSizeAndState(maxHeight, heightMeasureSpec,
+                        measuredChildState<<MEASURED_HEIGHT_STATE_SHIFT));
     }
 
     @Override
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index b45aa99..b9a9674 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -282,8 +282,12 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int width = getDefaultSize(mRequestedWidth, widthMeasureSpec);
-        int height = getDefaultSize(mRequestedHeight, heightMeasureSpec);
+        int width = mRequestedWidth >= 0
+                ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
+                : getDefaultSize(0, widthMeasureSpec);
+        int height = mRequestedHeight >= 0
+                ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
+                : getDefaultSize(0, heightMeasureSpec);
         setMeasuredDimension(width, height);
     }
     
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6114800..daf9ac4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -986,6 +986,33 @@
     public static final int FOCUS_DOWN = 0x00000082;
 
     /**
+     * Bits of {@link #getMeasuredWidthAndState()} and
+     * {@link #getMeasuredWidthAndState()} that provide the actual measured size.
+     */
+    public static final int MEASURED_SIZE_MASK = 0x00ffffff;
+
+    /**
+     * Bits of {@link #getMeasuredWidthAndState()} and
+     * {@link #getMeasuredWidthAndState()} that provide the additional state bits.
+     */
+    public static final int MEASURED_STATE_MASK = 0xff000000;
+
+    /**
+     * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits
+     * for functions that combine both width and height into a single int,
+     * such as {@link #getMeasuredState()} and the childState argument of
+     * {@link #resolveSizeAndState(int, int, int)}.
+     */
+    public static final int MEASURED_HEIGHT_STATE_SHIFT = 16;
+
+    /**
+     * Bit of {@link #getMeasuredWidthAndState()} and
+     * {@link #getMeasuredWidthAndState()} that indicates the measured size
+     * is smaller that the space the view would like to have.
+     */
+    public static final int MEASURED_STATE_TOO_SMALL = 0x01000000;
+
+    /**
      * Base View state sets
      */
     // Singles
@@ -1463,14 +1490,14 @@
      * {@hide}
      */
     @ViewDebug.ExportedProperty(category = "measurement")
-    protected int mMeasuredWidth;
+    /*package*/ int mMeasuredWidth;
 
     /**
      * Height as measured during measure pass.
      * {@hide}
      */
     @ViewDebug.ExportedProperty(category = "measurement")
-    protected int mMeasuredHeight;
+    /*package*/ int mMeasuredHeight;
 
     /**
      * The view's identifier.
@@ -5212,28 +5239,67 @@
     }
 
     /**
-     * The width of this view as measured in the most recent call to measure().
+     * Like {@link #getMeasuredWidthAndState()}, but only returns the
+     * raw width component (that is the result is masked by
+     * {@link #MEASURED_SIZE_MASK}).
+     *
+     * @return The raw measured width of this view.
+     */
+    public final int getMeasuredWidth() {
+        return mMeasuredWidth & MEASURED_SIZE_MASK;
+    }
+
+    /**
+     * Return the full width measurement information for this view as computed
+     * by the most recent call to {@link #measure}.  This result is a bit mask
+     * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}.
      * This should be used during measurement and layout calculations only. Use
      * {@link #getWidth()} to see how wide a view is after layout.
      *
-     * @return The measured width of this view.
+     * @return The measured width of this view as a bit mask.
      */
-    public final int getMeasuredWidth() {
+    public final int getMeasuredWidthAndState() {
         return mMeasuredWidth;
     }
 
     /**
-     * The height of this view as measured in the most recent call to measure().
-     * This should be used during measurement and layout calculations only. Use
-     * {@link #getHeight()} to see how tall a view is after layout.
+     * Like {@link #getMeasuredHeightAndState()}, but only returns the
+     * raw width component (that is the result is masked by
+     * {@link #MEASURED_SIZE_MASK}).
      *
-     * @return The measured height of this view.
+     * @return The raw measured height of this view.
      */
     public final int getMeasuredHeight() {
+        return mMeasuredHeight & MEASURED_SIZE_MASK;
+    }
+
+    /**
+     * Return the full height measurement information for this view as computed
+     * by the most recent call to {@link #measure}.  This result is a bit mask
+     * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}.
+     * This should be used during measurement and layout calculations only. Use
+     * {@link #getHeight()} to see how wide a view is after layout.
+     *
+     * @return The measured width of this view as a bit mask.
+     */
+    public final int getMeasuredHeightAndState() {
         return mMeasuredHeight;
     }
 
     /**
+     * Return only the state bits of {@link #getMeasuredWidthAndState()}
+     * and {@link #getMeasuredHeightAndState()}, combined into one integer.
+     * The width component is in the regular bits {@link #MEASURED_STATE_MASK}
+     * and the height component is at the shifted bits
+     * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}.
+     */
+    public final int getMeasuredState() {
+        return (mMeasuredWidth&MEASURED_STATE_MASK)
+                | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT)
+                        & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));
+    }
+
+    /**
      * The transform matrix of this view, which is calculated based on the current
      * roation, scale, and pivot properties.
      *
@@ -9690,8 +9756,12 @@
      * measured width and measured height. Failing to do so will trigger an
      * exception at measurement time.</p>
      *
-     * @param measuredWidth the measured width of this view
-     * @param measuredHeight the measured height of this view
+     * @param measuredWidth The measured width of this view.  May be a complex
+     * bit mask as defined by {@link #MEASURED_SIZE_MASK} and
+     * {@link #MEASURED_STATE_TOO_SMALL}.
+     * @param measuredHeight The measured height of this view.  May be a complex
+     * bit mask as defined by {@link #MEASURED_SIZE_MASK} and
+     * {@link #MEASURED_STATE_TOO_SMALL}.
      */
     protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
         mMeasuredWidth = measuredWidth;
@@ -9701,14 +9771,39 @@
     }
 
     /**
-     * Utility to reconcile a desired size with constraints imposed by a MeasureSpec.
-     * Will take the desired size, unless a different size is imposed by the constraints.
+     * Merge two states as returned by {@link #getMeasuredState()}.
+     * @param curState The current state as returned from a view or the result
+     * of combining multiple views.
+     * @param newState The new view state to combine.
+     * @return Returns a new integer reflecting the combination of the two
+     * states.
+     */
+    public static int combineMeasuredStates(int curState, int newState) {
+        return curState | newState;
+    }
+
+    /**
+     * Version of {@link #resolveSizeAndState(int, int, int)}
+     * returning only the {@link #MEASURED_SIZE_MASK} bits of the result.
+     */
+    public static int resolveSize(int size, int measureSpec) {
+        return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK;
+    }
+
+    /**
+     * Utility to reconcile a desired size and state, with constraints imposed
+     * by a MeasureSpec.  Will take the desired size, unless a different size
+     * is imposed by the constraints.  The returned value is a compound integer,
+     * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and
+     * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the resulting
+     * size is smaller than the size the view wants to be.
      *
      * @param size How big the view wants to be
      * @param measureSpec Constraints imposed by the parent
-     * @return The size this view should be.
+     * @return Size information bit mask as defined by
+     * {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}.
      */
-    public static int resolveSize(int size, int measureSpec) {
+    public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
         int result = size;
         int specMode = MeasureSpec.getMode(measureSpec);
         int specSize =  MeasureSpec.getSize(measureSpec);
@@ -9717,13 +9812,17 @@
             result = size;
             break;
         case MeasureSpec.AT_MOST:
-            result = Math.min(size, specSize);
+            if (specSize < size) {
+                result = specSize | MEASURED_STATE_TOO_SMALL;
+            } else {
+                result = size;
+            }
             break;
         case MeasureSpec.EXACTLY:
             result = specSize;
             break;
         }
-        return result;
+        return result | (childMeasuredState&MEASURED_STATE_MASK);
     }
 
     /**
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index dcde6ef..a34fe87 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -837,28 +837,23 @@
                 }
                 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
                 if (baseSize != 0 && desiredWindowWidth > baseSize) {
-                    int maxHeight = (desiredWindowHeight*2)/3;
                     childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
                     childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
                     host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
                     if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
-                            + host.getWidth() + "," + host.getHeight() + ")");
-                    // Note: for now we are not taking into account height, since we
-                    // can't distinguish between places where it would be useful to
-                    // increase the width (text) vs. where it would not (a list).
-                    // Maybe we can just try the next size up, and see if that reduces
-                    // the height?
-                    if (host.getWidth() <= baseSize /*&& host.getHeight() <= maxHeight*/) {
+                            + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
+                    if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
                         goodMeasure = true;
                     } else {
                         // Didn't fit in that size... try expanding a bit.
                         baseSize = (baseSize+desiredWindowWidth)/2;
                         if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
                                 + baseSize);
+                        childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
                         host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
                         if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
-                                + host.getWidth() + "," + host.getHeight() + ")");
-                        if (host.getWidth() <= baseSize /*&& host.getHeight() <= maxHeight*/) {
+                                + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
+                        if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
                             if (DEBUG_DIALOG) Log.v(TAG, "Good!");
                             goodMeasure = true;
                         }
@@ -924,7 +919,7 @@
         }
 
         boolean windowShouldResize = mLayoutRequested && windowSizeMayChange
-            && ((mWidth != host.mMeasuredWidth || mHeight != host.mMeasuredHeight)
+            && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
                 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
                         frame.width() < desiredWindowWidth && frame.width() != mWidth)
                 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
@@ -971,8 +966,8 @@
                     }
                 }
                 if (DEBUG_LAYOUT) {
-                    Log.i(TAG, "host=w:" + host.mMeasuredWidth + ", h:" +
-                            host.mMeasuredHeight + ", params=" + params);
+                    Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
+                            host.getMeasuredHeight() + ", params=" + params);
                 }
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
 
@@ -1112,15 +1107,15 @@
 
             boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
                     (relayoutResult&WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE) != 0);
-            if (focusChangedDueToTouchMode || mWidth != host.mMeasuredWidth
-                    || mHeight != host.mMeasuredHeight || contentInsetsChanged) {
+            if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
+                    || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
                 childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
                 childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
 
                 if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed!  mWidth="
-                        + mWidth + " measuredWidth=" + host.mMeasuredWidth
+                        + mWidth + " measuredWidth=" + host.getMeasuredWidth()
                         + " mHeight=" + mHeight
-                        + " measuredHeight" + host.mMeasuredHeight
+                        + " measuredHeight" + host.getMeasuredHeight()
                         + " coveredInsetsChanged=" + contentInsetsChanged);
 
                  // Ask host how big it wants to be
@@ -1129,8 +1124,8 @@
                 // Implementation of weights from WindowManager.LayoutParams
                 // We just grow the dimensions as needed and re-measure if
                 // needs be
-                int width = host.mMeasuredWidth;
-                int height = host.mMeasuredHeight;
+                int width = host.getMeasuredWidth();
+                int height = host.getMeasuredHeight();
                 boolean measureAgain = false;
 
                 if (lp.horizontalWeight > 0.0f) {
@@ -1165,12 +1160,12 @@
             mScrollMayChange = true;
             if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(
                 TAG, "Laying out " + host + " to (" +
-                host.mMeasuredWidth + ", " + host.mMeasuredHeight + ")");
+                host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
             long startTime = 0L;
             if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
                 startTime = SystemClock.elapsedRealtime();
             }
-            host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
+            host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
 
             if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
                 if (!host.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_LAYOUT)) {
@@ -2808,8 +2803,8 @@
         //Log.d(TAG, ">>>>>> CALLING relayout");
         int relayoutResult = sWindowSession.relayout(
                 mWindow, params,
-                (int) (mView.mMeasuredWidth * appScale + 0.5f),
-                (int) (mView.mMeasuredHeight * appScale + 0.5f),
+                (int) (mView.getMeasuredWidth() * appScale + 0.5f),
+                (int) (mView.getMeasuredHeight() * appScale + 0.5f),
                 viewVisibility, insetsPending, mWinFrame,
                 mPendingContentInsets, mPendingVisibleInsets,
                 mPendingConfiguration, mSurface);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index a9fa879..45d51d0 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -6472,6 +6472,8 @@
                 if (measuredHeight > heightSize) {
                     measuredHeight = heightSize;
                     mHeightCanMeasure = false;
+                } else if (measuredHeight < heightSize) {
+                    measuredHeight |= MEASURED_STATE_TOO_SMALL;
                 }
             }
         } else {
@@ -6485,6 +6487,9 @@
             mWidthCanMeasure = true;
             measuredWidth = contentWidth;
         } else {
+            if (measuredWidth < contentWidth) {
+                measuredWidth |= MEASURED_STATE_TOO_SMALL;
+            }
             mWidthCanMeasure = false;
         }
 
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 7340486..0da73a4 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -311,8 +311,8 @@
         dw += mPaddingLeft + mPaddingRight;
         dh += mPaddingTop + mPaddingBottom;
         
-        setMeasuredDimension(resolveSize(dw, widthMeasureSpec),
-                resolveSize(dh, heightMeasureSpec));
+        setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
+                resolveSizeAndState(dh, heightMeasureSpec, 0));
     }
     
     @Override
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index 2b3b98d..3d79205 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -223,8 +223,8 @@
         preferredHeight = Math.max(preferredHeight, getSuggestedMinimumHeight());
         preferredWidth = Math.max(preferredWidth, getSuggestedMinimumWidth());
 
-        heightSize = resolveSize(preferredHeight, heightMeasureSpec);
-        widthSize = resolveSize(preferredWidth, widthMeasureSpec);
+        heightSize = resolveSizeAndState(preferredHeight, heightMeasureSpec, 0);
+        widthSize = resolveSizeAndState(preferredWidth, widthMeasureSpec, 0);
 
         setMeasuredDimension(widthSize, heightSize);
         mHeightMeasureSpec = heightMeasureSpec;
diff --git a/core/java/android/widget/AbsoluteLayout.java b/core/java/android/widget/AbsoluteLayout.java
index 970cbe3..ac82af7 100644
--- a/core/java/android/widget/AbsoluteLayout.java
+++ b/core/java/android/widget/AbsoluteLayout.java
@@ -88,8 +88,8 @@
         maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
         maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
         
-        setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec),
-                resolveSize(maxHeight, heightMeasureSpec));
+        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, 0),
+                resolveSizeAndState(maxHeight, heightMeasureSpec, 0));
     }
 
     /**
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index 695ea6b..162b030 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -648,8 +648,8 @@
 
     private void measureChildren() {
         final int count = getChildCount();
-        final int childWidth = mMeasuredWidth - mPaddingLeft - mPaddingRight;
-        final int childHeight = mMeasuredHeight - mPaddingTop - mPaddingBottom;
+        final int childWidth = getMeasuredWidth() - mPaddingLeft - mPaddingRight;
+        final int childHeight = getMeasuredHeight() - mPaddingTop - mPaddingBottom;
 
         for (int i = 0; i < count; i++) {
             final View child = getChildAt(i);
@@ -674,16 +674,28 @@
             heightSpecSize = haveChildRefSize ? mReferenceChildHeight + mPaddingTop +
                     mPaddingBottom : 0;
         } else if (heightSpecMode == MeasureSpec.AT_MOST) {
-            heightSpecSize = haveChildRefSize ? Math.min(mReferenceChildHeight + mPaddingTop +
-                    mPaddingBottom, heightSpecSize) : 0;
+            if (haveChildRefSize) {
+                int height = mReferenceChildHeight + mPaddingTop + mPaddingBottom;
+                if (height > heightSpecSize) {
+                    heightSpecSize |= MEASURED_STATE_TOO_SMALL;
+                } else {
+                    heightSpecSize = height;
+                }
+            }
         }
 
         if (widthSpecMode == MeasureSpec.UNSPECIFIED) {
             widthSpecSize = haveChildRefSize ? mReferenceChildWidth + mPaddingLeft +
                     mPaddingRight : 0;
         } else if (heightSpecMode == MeasureSpec.AT_MOST) {
-            widthSpecSize = haveChildRefSize ? Math.min(mReferenceChildWidth + mPaddingLeft +
-                    mPaddingRight, widthSpecSize) : 0;
+            if (haveChildRefSize) {
+                int width = mReferenceChildWidth + mPaddingLeft + mPaddingRight;
+                if (width > widthSpecSize) {
+                    widthSpecSize |= MEASURED_STATE_TOO_SMALL;
+                } else {
+                    widthSpecSize = width;
+                }
+            }
         }
 
         setMeasuredDimension(widthSpecSize, heightSpecSize);
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index f847bc3..84ebec3 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -146,8 +146,8 @@
 
         float scale = Math.min(hScale, vScale);
 
-        setMeasuredDimension(resolveSize((int) (mDialWidth * scale), widthMeasureSpec),
-                resolveSize((int) (mDialHeight * scale), heightMeasureSpec));
+        setMeasuredDimension(resolveSizeAndState((int) (mDialWidth * scale), widthMeasureSpec, 0),
+                resolveSizeAndState((int) (mDialHeight * scale), heightMeasureSpec, 0));
     }
 
     @Override
diff --git a/core/java/android/widget/ButtonGroup.java b/core/java/android/widget/ButtonGroup.java
index 6af1c7e..7548ef6 100644
--- a/core/java/android/widget/ButtonGroup.java
+++ b/core/java/android/widget/ButtonGroup.java
@@ -167,12 +167,14 @@
 
         if (getOrientation() == VERTICAL) {
             final int dividerSize = mDividerHeight * dividerCount;
-            setMeasuredDimension(getMeasuredWidth(),
-                    resolveSize(getMeasuredHeight() + dividerSize, heightMeasureSpec));
+            setMeasuredDimension(getMeasuredWidthAndState(),
+                    resolveSizeAndState(getMeasuredHeight() + dividerSize, heightMeasureSpec,
+                            getMeasuredHeightAndState()));
         } else {
             final int dividerSize = mDividerWidth * dividerCount;
-            setMeasuredDimension(resolveSize(getMeasuredWidth() + dividerSize, widthMeasureSpec),
-                    getMeasuredHeight());
+            setMeasuredDimension(resolveSizeAndState(getMeasuredWidth() + dividerSize,
+                            widthMeasureSpec, getMeasuredWidthAndState()),
+                    getMeasuredHeightAndState());
         }
     }
 
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index bcab7a9..940fec1 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -248,6 +248,7 @@
 
         int maxHeight = 0;
         int maxWidth = 0;
+        int childState = 0;
 
         // Find rightmost and bottommost child
         for (int i = 0; i < count; i++) {
@@ -256,6 +257,7 @@
                 measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
                 maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
                 maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
+                childState = combineMeasuredStates(childState, child.getMeasuredState());
             }
         }
 
@@ -274,8 +276,9 @@
             maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
         }
 
-        setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec),
-                resolveSize(maxHeight, heightMeasureSpec));
+        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+                resolveSizeAndState(maxHeight, heightMeasureSpec,
+                        childState<<MEASURED_HEIGHT_STATE_SHIFT));
     }
  
     /**
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index 9789658..ce76bee 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -814,7 +814,7 @@
      * @return Where the top of the child should be
      */
     private int calculateTop(View child, boolean duringLayout) {
-        int myHeight = duringLayout ? mMeasuredHeight : getHeight();
+        int myHeight = duringLayout ? getMeasuredHeight() : getHeight();
         int childHeight = duringLayout ? child.getMeasuredHeight() : child.getHeight(); 
         
         int childTop = 0;
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 4146460..84bc5f2 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -979,6 +979,7 @@
         determineColumns(childWidth);
 
         int childHeight = 0;
+        int childState = 0;
 
         mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
         final int count = mItemCount;
@@ -1001,6 +1002,7 @@
             child.measure(childWidthSpec, childHeightSpec);
 
             childHeight = child.getMeasuredHeight();
+            childState = combineMeasuredStates(childState, child.getMeasuredState());
 
             if (mRecycler.shouldRecycleViewType(p.viewType)) {
                 mRecycler.addScrapView(child, -1);
@@ -1029,6 +1031,15 @@
             heightSize = ourSize;
         }
 
+        if (widthMode == MeasureSpec.AT_MOST && mRequestedNumColumns != AUTO_FIT) {
+            int ourSize = (mRequestedNumColumns*mColumnWidth)
+                    + ((mRequestedNumColumns-1)*mHorizontalSpacing)
+                    + mListPadding.left + mListPadding.right;
+            if (ourSize > widthSize) {
+                widthSize |= MEASURED_STATE_TOO_SMALL;
+            }
+        }
+
         setMeasuredDimension(widthSize, heightSize);
         mWidthMeasureSpec = widthMeasureSpec;
     }
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 555d993..1fe6f4b 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -696,7 +696,7 @@
                                             / desiredAspect) + ptop + pbottom;
                         if (newHeight <= heightSize) {
                             heightSize = newHeight;
-                        } 
+                        }
                     }
                 }
             }
@@ -711,8 +711,8 @@
             w = Math.max(w, getSuggestedMinimumWidth());
             h = Math.max(h, getSuggestedMinimumHeight());
 
-            widthSize = resolveSize(w, widthMeasureSpec);
-            heightSize = resolveSize(h, heightMeasureSpec);
+            widthSize = resolveSizeAndState(w, widthMeasureSpec, 0);
+            heightSize = resolveSizeAndState(h, heightMeasureSpec, 0);
         }
 
         setMeasuredDimension(widthSize, heightSize);
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 99b181f..a09e5c6 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -536,6 +536,7 @@
     void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
         mTotalLength = 0;
         int maxWidth = 0;
+        int childState = 0;
         int alternativeMaxWidth = 0;
         int weightedMaxWidth = 0;
         boolean allFillParent = true;
@@ -658,6 +659,7 @@
             final int margin = lp.leftMargin + lp.rightMargin;
             final int measuredWidth = child.getMeasuredWidth() + margin;
             maxWidth = Math.max(maxWidth, measuredWidth);
+            childState = combineMeasuredStates(childState, child.getMeasuredState());
 
             allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
             if (lp.weight > 0) {
@@ -713,7 +715,8 @@
         heightSize = Math.max(heightSize, getSuggestedMinimumHeight());
         
         // Reconcile our calculated size with the heightMeasureSpec
-        heightSize = resolveSize(heightSize, heightMeasureSpec);
+        int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);
+        heightSize = heightSizeAndState & MEASURED_SIZE_MASK;
         
         // Either expand children with weight to take up available space or
         // shrink them if they extend beyond our current bounds
@@ -762,6 +765,10 @@
                                 MeasureSpec.makeMeasureSpec(share > 0 ? share : 0,
                                         MeasureSpec.EXACTLY));
                     }
+
+                    // Child may now not fit in vertical dimension.
+                    childState = combineMeasuredStates(childState, child.getMeasuredState()
+                            & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));
                 }
 
                 final int margin =  lp.leftMargin + lp.rightMargin;
@@ -798,7 +805,8 @@
         // Check against our minimum width
         maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
         
-        setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), heightSize);
+        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+                heightSizeAndState);
 
         if (matchWidth) {
             forceUniformWidth(count, heightMeasureSpec);
@@ -842,6 +850,7 @@
     void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) {
         mTotalLength = 0;
         int maxHeight = 0;
+        int childState = 0;
         int alternativeMaxHeight = 0;
         int weightedMaxHeight = 0;
         boolean allFillParent = true;
@@ -978,6 +987,7 @@
 
             final int margin = lp.topMargin + lp.bottomMargin;
             final int childHeight = child.getMeasuredHeight() + margin;
+            childState = combineMeasuredStates(childState, child.getMeasuredState());
 
             if (baselineAligned) {
                 final int childBaseline = child.getBaseline();
@@ -1069,7 +1079,8 @@
         widthSize = Math.max(widthSize, getSuggestedMinimumWidth());
         
         // Reconcile our calculated size with the widthMeasureSpec
-        widthSize = resolveSize(widthSize, widthMeasureSpec);
+        int widthSizeAndState = resolveSizeAndState(widthSize, widthMeasureSpec, 0);
+        widthSize = widthSizeAndState & MEASURED_SIZE_MASK;
         
         // Either expand children with weight to take up available space or
         // shrink them if they extend beyond our current bounds
@@ -1124,6 +1135,10 @@
                                 share > 0 ? share : 0, MeasureSpec.EXACTLY),
                                 childHeightMeasureSpec);
                     }
+
+                    // Child may now not fit in horizontal dimension.
+                    childState = combineMeasuredStates(childState,
+                            child.getMeasuredState() & MEASURED_STATE_MASK);
                 }
 
                 if (isExactly) {
@@ -1193,7 +1208,9 @@
         // Check against our minimum height
         maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
         
-        setMeasuredDimension(widthSize, resolveSize(maxHeight, heightMeasureSpec));
+        setMeasuredDimension(widthSizeAndState | (childState&MEASURED_STATE_MASK),
+                resolveSizeAndState(maxHeight, heightMeasureSpec,
+                        (childState<<MEASURED_HEIGHT_STATE_SHIFT)));
 
         if (matchHeight) {
             forceUniformHeight(count, widthMeasureSpec);
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index c0721bc..3703846 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1102,6 +1102,7 @@
 
         int childWidth = 0;
         int childHeight = 0;
+        int childState = 0;
 
         mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
         if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED ||
@@ -1112,6 +1113,7 @@
 
             childWidth = child.getMeasuredWidth();
             childHeight = child.getMeasuredHeight();
+            childState = combineMeasuredStates(childState, child.getMeasuredState());
 
             if (recycleOnMeasure() && mRecycler.shouldRecycleViewType(
                     ((LayoutParams) child.getLayoutParams()).viewType)) {
@@ -1122,6 +1124,8 @@
         if (widthMode == MeasureSpec.UNSPECIFIED) {
             widthSize = mListPadding.left + mListPadding.right + childWidth +
                     getVerticalScrollbarWidth();
+        } else {
+            widthSize |= (childState&MEASURED_STATE_MASK);
         }
 
         if (heightMode == MeasureSpec.UNSPECIFIED) {
@@ -1134,7 +1138,7 @@
             heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
         }
 
-        setMeasuredDimension(widthSize, heightSize);
+        setMeasuredDimension(widthSize , heightSize);
         mWidthMeasureSpec = widthMeasureSpec;        
     }
 
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 63fb3e9..85ca5f3 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -891,8 +891,8 @@
         dw += mPaddingLeft + mPaddingRight;
         dh += mPaddingTop + mPaddingBottom;
 
-        setMeasuredDimension(resolveSize(dw, widthMeasureSpec),
-                resolveSize(dh, heightMeasureSpec));
+        setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
+                resolveSizeAndState(dh, heightMeasureSpec, 0));
     }
     
     @Override
diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java
index 28499d0..9e6ff4b 100644
--- a/core/java/android/widget/RatingBar.java
+++ b/core/java/android/widget/RatingBar.java
@@ -280,7 +280,8 @@
             // TODO: Once ProgressBar's TODOs are gone, this can be done more
             // cleanly than mSampleTile
             final int width = mSampleTile.getWidth() * mNumStars;
-            setMeasuredDimension(resolveSize(width, widthMeasureSpec), mMeasuredHeight);
+            setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0),
+                    getMeasuredHeight());
         }
     }
 
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 60422ae..006473e 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -357,7 +357,7 @@
 
         // Position vertically based on gravity setting
         int childTop = mSpinnerPadding.top
-                + ((mMeasuredHeight - mSpinnerPadding.bottom - 
+                + ((getMeasuredHeight() - mSpinnerPadding.bottom -
                         mSpinnerPadding.top - child.getMeasuredHeight()) / 2);
         int childBottom = childTop + child.getMeasuredHeight();
 
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index aee48c6..64fb985 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -281,7 +281,7 @@
     }
 
     private void transformViewAtIndex(int index, View view) {
-        float maxPerpectiveShift = mMeasuredHeight * PERSPECTIVE_SHIFT_FACTOR;
+        float maxPerpectiveShift = getMeasuredHeight() * PERSPECTIVE_SHIFT_FACTOR;
 
         index = mMaxNumActiveViews - index - 1;
         if (index == mMaxNumActiveViews - 1) index--;
@@ -297,7 +297,7 @@
         int stackDirection = (mStackMode == ITEMS_SLIDE_UP) ? 1 : -1;
         float perspectiveTranslation = -stackDirection * r * maxPerpectiveShift;
         float scaleShiftCorrection = stackDirection * (1 - scale) *
-                (mMeasuredHeight * (1 - PERSPECTIVE_SHIFT_FACTOR) / 2.0f);
+                (getMeasuredHeight() * (1 - PERSPECTIVE_SHIFT_FACTOR) / 2.0f);
         float transY = perspectiveTranslation + scaleShiftCorrection;
 
         PropertyValuesHolder translationY = PropertyValuesHolder.ofFloat("translationY", transY);
@@ -897,8 +897,8 @@
 
     private void measureChildren() {
         final int count = getChildCount();
-        final int childWidth = mMeasuredWidth - mPaddingLeft - mPaddingRight;
-        final int childHeight = Math.round(mMeasuredHeight*(1-PERSPECTIVE_SHIFT_FACTOR))
+        final int childWidth = getMeasuredWidth() - mPaddingLeft - mPaddingRight;
+        final int childHeight = Math.round(getMeasuredHeight()*(1-PERSPECTIVE_SHIFT_FACTOR))
                 - mPaddingTop - mPaddingBottom;
 
         for (int i = 0; i < count; i++) {
@@ -925,17 +925,33 @@
                     Math.round(mReferenceChildHeight * (1 + factor)) +
                     mPaddingTop + mPaddingBottom : 0;
         } else if (heightSpecMode == MeasureSpec.AT_MOST) {
-            heightSpecSize = haveChildRefSize ? Math.min(
-                    Math.round(mReferenceChildHeight * (1 + factor)) + mPaddingTop +
-                    mPaddingBottom, heightSpecSize) : 0;
+            if (haveChildRefSize) {
+                int height = Math.round(mReferenceChildHeight * (1 + factor))
+                        + mPaddingTop + mPaddingBottom;
+                if (height <= heightSpecSize) {
+                    heightSpecSize = height;
+                } else {
+                    heightSpecSize |= MEASURED_STATE_TOO_SMALL;
+                }
+            } else {
+                heightSpecSize = 0;
+            }
         }
 
         if (widthSpecMode == MeasureSpec.UNSPECIFIED) {
             widthSpecSize = haveChildRefSize ? mReferenceChildWidth + mPaddingLeft +
                     mPaddingRight : 0;
         } else if (heightSpecMode == MeasureSpec.AT_MOST) {
-            widthSpecSize = haveChildRefSize ? Math.min(mReferenceChildWidth + mPaddingLeft +
-                    mPaddingRight, widthSpecSize) : 0;
+            if (haveChildRefSize) {
+                int width = mReferenceChildWidth + mPaddingLeft + mPaddingRight;
+                if (width <= widthSpecSize) {
+                    widthSpecSize = width;
+                } else {
+                    widthSpecSize |= MEASURED_STATE_TOO_SMALL;
+                }
+            } else {
+                widthSpecSize = 0;
+            }
         }
 
         setMeasuredDimension(widthSpecSize, heightSpecSize);
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 73a8c66..4223040 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -359,10 +359,9 @@
         mSwitchHeight = switchHeight;
 
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        final int measuredWidth = getMeasuredWidth();
         final int measuredHeight = getMeasuredHeight();
         if (measuredHeight < switchHeight) {
-            setMeasuredDimension(measuredWidth, switchHeight);
+            setMeasuredDimension(getMeasuredWidthAndState(), switchHeight);
         }
     }
 
diff --git a/core/java/com/android/internal/view/menu/IconMenuView.java b/core/java/com/android/internal/view/menu/IconMenuView.java
index 178dcde..d18c9727 100644
--- a/core/java/com/android/internal/view/menu/IconMenuView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuView.java
@@ -486,7 +486,7 @@
 
         // Position the children
         if (layoutNumRows > 0) {
-            positionChildren(mMeasuredWidth, mMeasuredHeight);
+            positionChildren(getMeasuredWidth(), getMeasuredHeight());
         }
     }