From 7da4b73a236b7c72d1337696949df7a00776dd06 Mon Sep 17 00:00:00 2001 From: Adam Powell Date: Fri, 7 Dec 2012 15:28:33 -0800 Subject: [PATCH] Compatibility measurement hacks when targetSdkVersion <= JB-MR1 All three of these are interrelated! * Allow broken MeasureSpec values. The long-standing implementation of MeasureSpec.makeMeasureSpec has been to add both values rather than masking/or-ing the values together. Some old code relied on this, such as if it mixed up size/mode params. * Disable ImageView adjustViewBounds allowing the view to grow beyond its initial size. A bug in RelativeLayout in the presence of the above MeasureSpec fix causes this not to work properly in apps. * Allow RelativeLayout to send overflowed/bogus MeasureSpec values when measured with MeasureSpec.UNSPECIFIED mode. Some apps have custom child views that do not properly handle UNSPECIFIED measurements, but the exact overflow semantics caused this to generate AT_MOST $REALLYBIG MeasureSpecs for those views instead if they were placed inside a RelativeLayout in a scrolling container. Change-Id: I977a5f1ba5637f0cba3d26a70139e2bcd021fc9c --- core/java/android/view/View.java | 15 ++++++++++++++- core/java/android/widget/ImageView.java | 10 ++++++++-- core/java/android/widget/RelativeLayout.java | 16 ++++++++++++++-- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 63019bdad3e67..40eaa7ab89acd 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -40,6 +40,7 @@ import android.graphics.Shader; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManagerGlobal; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -688,6 +689,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public static final int NO_ID = -1; + private static boolean sUseBrokenMakeMeasureSpec = false; + /** * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when * calling setFlags. @@ -3234,6 +3237,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); mUserPaddingStart = UNDEFINED_PADDING; mUserPaddingEnd = UNDEFINED_PADDING; + + if (!sUseBrokenMakeMeasureSpec && context.getApplicationInfo().targetSdkVersion <= + Build.VERSION_CODES.JELLY_BEAN_MR1 ) { + // Older apps may need this compatibility hack for measurement. + sUseBrokenMakeMeasureSpec = true; + } } /** @@ -17327,7 +17336,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return the measure specification based on size and mode */ public static int makeMeasureSpec(int size, int mode) { - return (size & ~MODE_MASK) | (mode & MODE_MASK); + if (sUseBrokenMakeMeasureSpec) { + return size + mode; + } else { + return (size & ~MODE_MASK) | (mode & MODE_MASK); + } } /** diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index e3f0960b79633..aa977a1810c9a 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -30,6 +30,7 @@ import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Build; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; @@ -93,6 +94,9 @@ public class ImageView extends View { private int mBaseline = -1; private boolean mBaselineAlignBottom = false; + // AdjustViewBounds behavior will be in compatibility mode for older apps. + private boolean mAdjustViewBoundsCompat = false; + private static final ScaleType[] sScaleTypeArray = { ScaleType.MATRIX, ScaleType.FIT_XY, @@ -167,6 +171,8 @@ public class ImageView extends View { private void initImageView() { mMatrix = new Matrix(); mScaleType = ScaleType.FIT_CENTER; + mAdjustViewBoundsCompat = mContext.getApplicationInfo().targetSdkVersion <= + Build.VERSION_CODES.JELLY_BEAN_MR1; } @Override @@ -801,7 +807,7 @@ public class ImageView extends View { pleft + pright; // Allow the width to outgrow its original estimate if height is fixed. - if (!resizeHeight) { + if (!resizeHeight && !mAdjustViewBoundsCompat) { widthSize = resolveAdjustedSize(newWidth, mMaxWidth, widthMeasureSpec); } @@ -817,7 +823,7 @@ public class ImageView extends View { ptop + pbottom; // Allow the height to outgrow its original estimate if width is fixed. - if (!resizeWidth) { + if (!resizeWidth && !mAdjustViewBoundsCompat) { heightSize = resolveAdjustedSize(newHeight, mMaxHeight, heightMeasureSpec); } diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index a5eb28143fb51..6021975050ad6 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -29,6 +29,7 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Rect; +import android.os.Build; import android.util.AttributeSet; import android.util.Pools.SimplePool; import android.util.SparseArray; @@ -199,18 +200,29 @@ public class RelativeLayout extends ViewGroup { private View[] mSortedVerticalChildren = new View[0]; private final DependencyGraph mGraph = new DependencyGraph(); + // Compatibility hack. Old versions of the platform had problems + // with MeasureSpec value overflow and RelativeLayout was one source of them. + // Some apps came to rely on them. :( + private boolean mAllowBrokenMeasureSpecs = false; + public RelativeLayout(Context context) { super(context); + mAllowBrokenMeasureSpecs = context.getApplicationInfo().targetSdkVersion <= + Build.VERSION_CODES.JELLY_BEAN_MR1; } public RelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); initFromAttributes(context, attrs); + mAllowBrokenMeasureSpecs = context.getApplicationInfo().targetSdkVersion <= + Build.VERSION_CODES.JELLY_BEAN_MR1; } public RelativeLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initFromAttributes(context, attrs); + mAllowBrokenMeasureSpecs = context.getApplicationInfo().targetSdkVersion <= + Build.VERSION_CODES.JELLY_BEAN_MR1; } private void initFromAttributes(Context context, AttributeSet attrs) { @@ -660,7 +672,7 @@ public class RelativeLayout extends ViewGroup { mPaddingLeft, mPaddingRight, myWidth); int childHeightMeasureSpec; - if (myHeight < 0) { + if (myHeight < 0 && !mAllowBrokenMeasureSpecs) { // Negative values in a mySize/myWidth/myWidth value in RelativeLayout measurement // is code for, "we got an unspecified mode in the RelativeLayout's measurespec." // Carry it forward. @@ -692,7 +704,7 @@ public class RelativeLayout extends ViewGroup { private int getChildMeasureSpec(int childStart, int childEnd, int childSize, int startMargin, int endMargin, int startPadding, int endPadding, int mySize) { - if (mySize < 0) { + if (mySize < 0 && !mAllowBrokenMeasureSpecs) { // Negative values in a mySize/myWidth/myWidth value in RelativeLayout measurement // is code for, "we got an unspecified mode in the RelativeLayout's measurespec." // Carry it forward.