From 9a04856d5ecb07dea564feae2942fd485b53f3dd Mon Sep 17 00:00:00 2001 From: Fabrice Di Meglio Date: Wed, 26 Sep 2012 14:55:56 -0700 Subject: [PATCH] Other improvements for bug #6427629 Clean up layout direction APIs - hide isLayoutRtl() from public API - canResolveXXX() is now smarter: use recursion to get its returned value - in ViewGroup, if resolution cannot be done then dont ask resolution for its children - in ViewGroup, addViewInner() needs to ask to resolve the child. This is needed for example by ListView which is using the same measurespec before and after its childs being attached. It also take care of the general case where a measure pass is done when not attached to a parent (and thus asking for resolution that will "fail" if we are using IHNERIT) and never done again. That would lead to never do a resolution. - some code refactoring Change-Id: I120dd2fef7397944f5ba8deff0686b108dc827d2 --- api/current.txt | 1 - core/java/android/view/View.java | 138 +++++++++++++++----------- core/java/android/view/ViewGroup.java | 59 ++++++----- 3 files changed, 115 insertions(+), 83 deletions(-) diff --git a/api/current.txt b/api/current.txt index 177b787059685..96ec52e384c23 100644 --- a/api/current.txt +++ b/api/current.txt @@ -25038,7 +25038,6 @@ package android.view { method public boolean isInEditMode(); method public boolean isInTouchMode(); method public boolean isLayoutRequested(); - method public boolean isLayoutRtl(); method public boolean isLongClickable(); method public boolean isOpaque(); method protected boolean isPaddingOffsetRequired(); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 12eb800fc3a33..c9291ba19c1c1 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -5859,6 +5859,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * layout attribute and/or the inherited value from the parent * * @return true if the layout is right-to-left. + * + * @hide */ @ViewDebug.ExportedProperty(category = "layout") public boolean isLayoutRtl() { @@ -11591,9 +11593,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing * that the parent directionality can and will be resolved before its children. * + * @return true if resolution has been done, false otherwise. + * * @hide */ - public void resolveLayoutDirection() { + public boolean resolveLayoutDirection() { // Clear any previous layout direction resolution mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; @@ -11604,15 +11608,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, case LAYOUT_DIRECTION_INHERIT: // We cannot resolve yet. LTR is by default and let the resolution happen again // later to get the correct resolved value - if (!canResolveLayoutDirection()) return; + if (!canResolveLayoutDirection()) return false; - ViewGroup viewGroup = ((ViewGroup) mParent); + View parent = ((View) mParent); + // Parent has not yet resolved, LTR is still the default + if (!parent.isLayoutDirectionResolved()) return false; - // We cannot resolve yet on the parent too. LTR is by default and let the - // resolution happen again later - if (!viewGroup.canResolveLayoutDirection()) return; - - if (viewGroup.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { + if (parent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; } break; @@ -11632,6 +11634,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // Set to resolved mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; + return true; } /** @@ -11642,10 +11645,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ public boolean canResolveLayoutDirection() { - switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> - PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { + switch (getRawLayoutDirection()) { case LAYOUT_DIRECTION_INHERIT: - return (mParent != null) && (mParent instanceof ViewGroup); + return (mParent != null) && (mParent instanceof ViewGroup) && + ((ViewGroup) mParent).canResolveLayoutDirection(); default: return true; } @@ -16622,9 +16625,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Resolve the text direction. * + * @return true if resolution has been done, false otherwise. + * * @hide */ - public void resolveTextDirection() { + public boolean resolveTextDirection() { // Reset any previous text direction resolution mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); @@ -16633,29 +16638,35 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final int textDirection = getRawTextDirection(); switch(textDirection) { case TEXT_DIRECTION_INHERIT: - if (canResolveTextDirection()) { - ViewGroup viewGroup = ((ViewGroup) mParent); - - // Set current resolved direction to the same value as the parent's one - final int parentResolvedDirection = viewGroup.getTextDirection(); - switch (parentResolvedDirection) { - case TEXT_DIRECTION_FIRST_STRONG: - case TEXT_DIRECTION_ANY_RTL: - case TEXT_DIRECTION_LTR: - case TEXT_DIRECTION_RTL: - case TEXT_DIRECTION_LOCALE: - mPrivateFlags2 |= - (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); - break; - default: - // Default resolved direction is "first strong" heuristic - mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; - } - } else { + if (!canResolveTextDirection()) { // We cannot do the resolution if there is no parent, so use the default one mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; // Resolution will need to happen again later - return; + return false; + } + + View parent = ((View) mParent); + // Parent has not yet resolved, so we still return the default + if (!parent.isTextDirectionResolved()) { + mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; + // Resolution will need to happen again later + return false; + } + + // Set current resolved direction to the same value as the parent's one + final int parentResolvedDirection = parent.getTextDirection(); + switch (parentResolvedDirection) { + case TEXT_DIRECTION_FIRST_STRONG: + case TEXT_DIRECTION_ANY_RTL: + case TEXT_DIRECTION_LTR: + case TEXT_DIRECTION_RTL: + case TEXT_DIRECTION_LOCALE: + mPrivateFlags2 |= + (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); + break; + default: + // Default resolved direction is "first strong" heuristic + mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; } break; case TEXT_DIRECTION_FIRST_STRONG: @@ -16677,6 +16688,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // Set to resolved mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; + return true; } /** @@ -16687,7 +16699,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private boolean canResolveTextDirection() { switch (getRawTextDirection()) { case TEXT_DIRECTION_INHERIT: - return (mParent != null) && (mParent instanceof ViewGroup); + return (mParent != null) && (mParent instanceof View) && + ((View) mParent).canResolveTextDirection(); default: return true; } @@ -16817,9 +16830,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Resolve the text alignment. * + * @return true if resolution has been done, false otherwise. + * * @hide */ - public void resolveTextAlignment() { + public boolean resolveTextAlignment() { // Reset any previous text alignment resolution mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); @@ -16829,32 +16844,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback, switch (textAlignment) { case TEXT_ALIGNMENT_INHERIT: // Check if we can resolve the text alignment - if (canResolveTextAlignment() && mParent instanceof View) { - View view = (View) mParent; - - final int parentResolvedTextAlignment = view.getTextAlignment(); - switch (parentResolvedTextAlignment) { - case TEXT_ALIGNMENT_GRAVITY: - case TEXT_ALIGNMENT_TEXT_START: - case TEXT_ALIGNMENT_TEXT_END: - case TEXT_ALIGNMENT_CENTER: - case TEXT_ALIGNMENT_VIEW_START: - case TEXT_ALIGNMENT_VIEW_END: - // Resolved text alignment is the same as the parent resolved - // text alignment - mPrivateFlags2 |= - (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); - break; - default: - // Use default resolved text alignment - mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; - } - } - else { + if (!canResolveTextAlignment()) { // We cannot do the resolution if there is no parent so use the default mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; // Resolution will need to happen again later - return; + return false; + } + View parent = (View) mParent; + + // Parent has not yet resolved, so we still return the default + if (!parent.isTextAlignmentResolved()) { + mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; + // Resolution will need to happen again later + return false; + } + + final int parentResolvedTextAlignment = parent.getTextAlignment(); + switch (parentResolvedTextAlignment) { + case TEXT_ALIGNMENT_GRAVITY: + case TEXT_ALIGNMENT_TEXT_START: + case TEXT_ALIGNMENT_TEXT_END: + case TEXT_ALIGNMENT_CENTER: + case TEXT_ALIGNMENT_VIEW_START: + case TEXT_ALIGNMENT_VIEW_END: + // Resolved text alignment is the same as the parent resolved + // text alignment + mPrivateFlags2 |= + (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); + break; + default: + // Use default resolved text alignment + mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; } break; case TEXT_ALIGNMENT_GRAVITY: @@ -16877,6 +16897,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // Set the resolved mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; + return true; } /** @@ -16887,7 +16908,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private boolean canResolveTextAlignment() { switch (getRawTextAlignment()) { case TEXT_DIRECTION_INHERIT: - return (mParent != null); + return (mParent != null) && (mParent instanceof View) && + ((View) mParent).canResolveTextAlignment(); default: return true; } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 41890d6ee3d43..f1d0cc0d58504 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -3382,6 +3382,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager ai.mKeepScreenOn = lastKeepOn; } + if (child.isLayoutDirectionInherited()) { + child.resetResolvedLayoutDirection(); + child.resolveRtlPropertiesIfNeeded(); + } + onViewAdded(child); if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) { @@ -5256,48 +5261,54 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * @hide */ @Override - public void resolveLayoutDirection() { - super.resolveLayoutDirection(); - - int count = getChildCount(); - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - if (child.isLayoutDirectionInherited()) { - child.resolveLayoutDirection(); + public boolean resolveLayoutDirection() { + final boolean result = super.resolveLayoutDirection(); + if (result) { + int count = getChildCount(); + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.isLayoutDirectionInherited()) { + child.resolveLayoutDirection(); + } } } + return result; } /** * @hide */ @Override - public void resolveTextDirection() { - super.resolveTextDirection(); - - int count = getChildCount(); - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - if (child.isTextDirectionInherited()) { - child.resolveTextDirection(); + public boolean resolveTextDirection() { + final boolean result = super.resolveTextDirection(); + if (result) { + int count = getChildCount(); + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.isTextDirectionInherited()) { + child.resolveTextDirection(); + } } } + return result; } /** * @hide */ @Override - public void resolveTextAlignment() { - super.resolveTextAlignment(); - - int count = getChildCount(); - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - if (child.isTextAlignmentInherited()) { - child.resolveTextAlignment(); + public boolean resolveTextAlignment() { + final boolean result = super.resolveTextAlignment(); + if (result) { + int count = getChildCount(); + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.isTextAlignmentInherited()) { + child.resolveTextAlignment(); + } } } + return result; } /**