Improve resolution of RTL related properties
- fix bug #6887370 ListPreference shows misaligned radio drawables (in CheckedTextView?)
- fix bug #6938146 "Show more cards..." text on bottom button is not centered
- also defer scrollbar initialization as we need resolved padding values for them
Change-Id: Ife651ffe6bbcc228ff6724f3d9b91079fac3a740
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 59aeffc..2f2c906 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2790,6 +2790,20 @@
int mUserPaddingEnd;
/**
+ * Whether a left padding has been defined during layout inflation.
+ *
+ * @hide
+ */
+ boolean mUserPaddingLeftDefined = false;
+
+ /**
+ * Whether a right padding has been defined during layout inflation.
+ *
+ * @hide
+ */
+ boolean mUserPaddingRightDefined = false;
+
+ /**
* Default undefined padding
*/
private static final int UNDEFINED_PADDING = Integer.MIN_VALUE;
@@ -3195,8 +3209,11 @@
boolean transformSet = false;
int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY;
-
int overScrollMode = mOverScrollMode;
+ boolean initializeScrollbars = false;
+
+ final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
+
final int N = a.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = a.getIndex(i);
@@ -3206,15 +3223,19 @@
break;
case com.android.internal.R.styleable.View_padding:
padding = a.getDimensionPixelSize(attr, -1);
+ mUserPaddingLeftDefined = true;
+ mUserPaddingRightDefined = true;
break;
case com.android.internal.R.styleable.View_paddingLeft:
leftPadding = a.getDimensionPixelSize(attr, -1);
+ mUserPaddingLeftDefined = true;
break;
case com.android.internal.R.styleable.View_paddingTop:
topPadding = a.getDimensionPixelSize(attr, -1);
break;
case com.android.internal.R.styleable.View_paddingRight:
rightPadding = a.getDimensionPixelSize(attr, -1);
+ mUserPaddingRightDefined = true;
break;
case com.android.internal.R.styleable.View_paddingBottom:
bottomPadding = a.getDimensionPixelSize(attr, -1);
@@ -3359,12 +3380,12 @@
if (scrollbars != SCROLLBARS_NONE) {
viewFlagValues |= scrollbars;
viewFlagMasks |= SCROLLBARS_MASK;
- initializeScrollbars(a);
+ initializeScrollbars = true;
}
break;
//noinspection deprecation
case R.styleable.View_fadingEdge:
- if (context.getApplicationInfo().targetSdkVersion >= ICE_CREAM_SANDWICH) {
+ if (targetSdkVersion >= ICE_CREAM_SANDWICH) {
// Ignore the attribute starting with ICS
break;
}
@@ -3496,12 +3517,11 @@
}
}
- a.recycle();
-
setOverScrollMode(overScrollMode);
- // Cache user padding as we cannot fully resolve padding here (we dont have yet the resolved
- // layout direction). Those cached values will be used later during padding resolution.
+ // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet
+ // the resolved layout direction). Those cached values will be used later during padding
+ // resolution.
mUserPaddingStart = startPadding;
mUserPaddingEnd = endPadding;
@@ -3529,6 +3549,12 @@
setFlags(viewFlagValues, viewFlagMasks);
}
+ if (initializeScrollbars) {
+ initializeScrollbars(a);
+ }
+
+ a.recycle();
+
// Needs to be called after mViewFlags is set
if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) {
recomputePadding();
@@ -5533,10 +5559,13 @@
// Reset the current layout direction and the resolved one
mPrivateFlags2 &= ~LAYOUT_DIRECTION_MASK;
resetResolvedLayoutDirection();
- // Set the new layout direction (filtered) and ask for a layout pass
+ // Reset padding resolution
+ mPrivateFlags2 &= ~PADDING_RESOLVED;
+ // Set the new layout direction (filtered)
mPrivateFlags2 |=
((layoutDirection << LAYOUT_DIRECTION_MASK_SHIFT) & LAYOUT_DIRECTION_MASK);
- resolvePadding();
+ resolveRtlProperties();
+ // ... and ask for a layout pass
requestLayout();
}
}
@@ -5552,6 +5581,11 @@
@ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL")
})
public int getResolvedLayoutDirection() {
+ final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
+ if (targetSdkVersion < JELLY_BEAN_MR1) {
+ mPrivateFlags2 |= LAYOUT_DIRECTION_RESOLVED;
+ return LAYOUT_DIRECTION_LTR;
+ }
// The layout direction will be resolved only if needed
if ((mPrivateFlags2 & LAYOUT_DIRECTION_RESOLVED) != LAYOUT_DIRECTION_RESOLVED) {
resolveLayoutDirection();
@@ -9657,6 +9691,7 @@
throw new NullPointerException("Layout parameters cannot be null");
}
mLayoutParams = params;
+ resolveLayoutParams();
if (mParent instanceof ViewGroup) {
((ViewGroup) mParent).onSetLayoutParams(this, params);
}
@@ -9664,6 +9699,15 @@
}
/**
+ * Resolve the layout parameters depending on the resolved layout direction
+ */
+ private void resolveLayoutParams() {
+ if (mLayoutParams != null) {
+ mLayoutParams.onResolveLayoutDirection(getResolvedLayoutDirection());
+ }
+ }
+
+ /**
* Set the scrolled position of your view. This will cause a call to
* {@link #onScrollChanged(int, int, int, int)} and the view will be
* invalidated.
@@ -11197,12 +11241,7 @@
jumpDrawablesToCurrentState();
- // Order is important here: LayoutDirection MUST be resolved before Padding
- // and TextDirection
- resolveLayoutDirection();
- resolvePadding();
- resolveTextDirection();
- resolveTextAlignment();
+ resolveRtlProperties();
clearAccessibilityFocus();
if (isFocused()) {
@@ -11215,6 +11254,16 @@
}
}
+ void resolveRtlProperties() {
+ // Order is important here: LayoutDirection MUST be resolved first...
+ resolveLayoutDirection();
+ // ... then we can resolve the others properties depending on the resolved LayoutDirection.
+ resolvePadding();
+ resolveLayoutParams();
+ resolveTextDirection();
+ resolveTextAlignment();
+ }
+
/**
* @see #onScreenStateChanged(int)
*/
@@ -11295,55 +11344,65 @@
}
/**
+ * Return if padding has been resolved
+ */
+ boolean isPaddingResolved() {
+ return (mPrivateFlags2 & PADDING_RESOLVED) != 0;
+ }
+
+ /**
* Resolve padding depending on layout direction.
*/
public void resolvePadding() {
- // If the user specified the absolute padding (either with android:padding or
- // android:paddingLeft/Top/Right/Bottom), use this padding, otherwise
- // use the default padding or the padding from the background drawable
- // (stored at this point in mPadding*)
- int resolvedLayoutDirection = getResolvedLayoutDirection();
- switch (resolvedLayoutDirection) {
- case LAYOUT_DIRECTION_RTL:
- // Start user padding override Right user padding. Otherwise, if Right user
- // padding is not defined, use the default Right padding. If Right user padding
- // is defined, just use it.
- if (mUserPaddingStart != UNDEFINED_PADDING) {
- mUserPaddingRight = mUserPaddingStart;
- }
- if (mUserPaddingRight == UNDEFINED_PADDING) {
- mUserPaddingRight = mPaddingRight;
- }
- if (mUserPaddingEnd != UNDEFINED_PADDING) {
- mUserPaddingLeft = mUserPaddingEnd;
- }
- if (mUserPaddingLeft == UNDEFINED_PADDING) {
- mUserPaddingLeft = mPaddingLeft;
- }
- break;
- case LAYOUT_DIRECTION_LTR:
- default:
- // Start user padding override Left user padding. Otherwise, if Left user
- // padding is not defined, use the default left padding. If Left user padding
- // is defined, just use it.
- if (mUserPaddingStart != UNDEFINED_PADDING) {
- mUserPaddingLeft = mUserPaddingStart;
- }
- if (mUserPaddingLeft == UNDEFINED_PADDING) {
- mUserPaddingLeft = mPaddingLeft;
- }
- if (mUserPaddingEnd != UNDEFINED_PADDING) {
- mUserPaddingRight = mUserPaddingEnd;
- }
- if (mUserPaddingRight == UNDEFINED_PADDING) {
- mUserPaddingRight = mPaddingRight;
- }
+ final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
+ if (targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport()) {
+ // Pre Jelly Bean MR1 case (compatibility mode) OR no RTL support case:
+ // left / right padding are used if defined. If they are not defined and start / end
+ // padding are defined (e.g. in Frameworks resources), then we use start / end and
+ // resolve them as left / right (layout direction is not taken into account).
+ if (!mUserPaddingLeftDefined && mUserPaddingStart != UNDEFINED_PADDING) {
+ mUserPaddingLeft = mUserPaddingStart;
+ }
+ if (!mUserPaddingRightDefined && mUserPaddingEnd != UNDEFINED_PADDING) {
+ mUserPaddingRight = mUserPaddingEnd;
+ }
+
+ mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom;
+
+ internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight,
+ mUserPaddingBottom);
+ } else {
+ // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account.
+ // If start / end padding are defined, they will be resolved (hence overriding) to
+ // left / right or right / left depending on the resolved layout direction.
+ // If start / end padding are not defined, use the left / right ones.
+ int resolvedLayoutDirection = getResolvedLayoutDirection();
+ switch (resolvedLayoutDirection) {
+ case LAYOUT_DIRECTION_RTL:
+ if (mUserPaddingStart != UNDEFINED_PADDING) {
+ mUserPaddingRight = mUserPaddingStart;
+ }
+ if (mUserPaddingEnd != UNDEFINED_PADDING) {
+ mUserPaddingLeft = mUserPaddingEnd;
+ }
+ break;
+ case LAYOUT_DIRECTION_LTR:
+ default:
+ if (mUserPaddingStart != UNDEFINED_PADDING) {
+ mUserPaddingLeft = mUserPaddingStart;
+ }
+ if (mUserPaddingEnd != UNDEFINED_PADDING) {
+ mUserPaddingRight = mUserPaddingEnd;
+ }
+ }
+
+ mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom;
+
+ internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight,
+ mUserPaddingBottom);
+ onPaddingChanged(resolvedLayoutDirection);
}
- mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom;
-
- internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom);
- onPaddingChanged(resolvedLayoutDirection);
mPrivateFlags2 |= PADDING_RESOLVED;
}
@@ -14016,6 +14075,8 @@
}
background.setLayoutDirection(getResolvedLayoutDirection());
if (background.getPadding(padding)) {
+ // Reset padding resolution
+ mPrivateFlags2 &= ~PADDING_RESOLVED;
switch (background.getLayoutDirection()) {
case LAYOUT_DIRECTION_RTL:
internalSetPadding(padding.right, padding.top, padding.left, padding.bottom);
@@ -14112,13 +14173,19 @@
* @param bottom the bottom padding in pixels
*/
public void setPadding(int left, int top, int right, int bottom) {
+ // Reset padding resolution
+ mPrivateFlags2 &= ~PADDING_RESOLVED;
+
mUserPaddingStart = UNDEFINED_PADDING;
mUserPaddingEnd = UNDEFINED_PADDING;
internalSetPadding(left, top, right, bottom);
}
- void internalSetPadding(int left, int top, int right, int bottom) {
+ /**
+ * @hide
+ */
+ protected void internalSetPadding(int left, int top, int right, int bottom) {
mUserPaddingLeft = left;
mUserPaddingRight = right;
mUserPaddingBottom = bottom;
@@ -14193,6 +14260,9 @@
* @param bottom the bottom padding in pixels
*/
public void setPaddingRelative(int start, int top, int end, int bottom) {
+ // Reset padding resolution
+ mPrivateFlags2 &= ~PADDING_RESOLVED;
+
mUserPaddingStart = start;
mUserPaddingEnd = end;
@@ -14234,6 +14304,9 @@
* @return the left padding in pixels
*/
public int getPaddingLeft() {
+ if (!isPaddingResolved()) {
+ resolvePadding();
+ }
return mPaddingLeft;
}
@@ -14245,6 +14318,9 @@
* @return the start padding in pixels
*/
public int getPaddingStart() {
+ if (!isPaddingResolved()) {
+ resolvePadding();
+ }
return (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
mPaddingRight : mPaddingLeft;
}
@@ -14257,6 +14333,9 @@
* @return the right padding in pixels
*/
public int getPaddingRight() {
+ if (!isPaddingResolved()) {
+ resolvePadding();
+ }
return mPaddingRight;
}
@@ -14268,6 +14347,9 @@
* @return the end padding in pixels
*/
public int getPaddingEnd() {
+ if (!isPaddingResolved()) {
+ resolvePadding();
+ }
return (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
mPaddingLeft : mPaddingRight;
}
@@ -14913,10 +14995,6 @@
mPrivateFlags |= FORCE_LAYOUT;
mPrivateFlags |= INVALIDATED;
- if (mLayoutParams != null) {
- mLayoutParams.onResolveLayoutDirection(getResolvedLayoutDirection());
- }
-
if (mParent != null && !mParent.isLayoutRequested()) {
mParent.requestLayout();
}
@@ -14960,7 +15038,7 @@
// first clears the measured dimension flag
mPrivateFlags &= ~MEASURED_DIMENSION_SET;
- if ((mPrivateFlags2 & PADDING_RESOLVED) == 0) {
+ if (!isPaddingResolved()) {
resolvePadding();
}