diff options
20 files changed, 311 insertions, 70 deletions
diff --git a/api/current.txt b/api/current.txt index dffb868..7dcb714 100644 --- a/api/current.txt +++ b/api/current.txt @@ -8331,6 +8331,7 @@ package android.graphics.drawable { method public android.graphics.Region getTransparentRegion(); method public void inflate(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public void invalidateSelf(); + method public boolean isLayoutRtlSelf(); method public boolean isStateful(); method public final boolean isVisible(); method public void jumpToCurrentState(); @@ -8361,6 +8362,10 @@ package android.graphics.drawable { method public abstract void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable); } + public static abstract interface Drawable.Callback2 implements android.graphics.drawable.Drawable.Callback { + method public abstract boolean isLayoutRtl(android.graphics.drawable.Drawable); + } + public static abstract class Drawable.ConstantState { ctor public Drawable.ConstantState(); method public abstract int getChangingConfigurations(); @@ -20136,14 +20141,17 @@ package android.view { method public static void apply(int, int, int, android.graphics.Rect, android.graphics.Rect); method public static void apply(int, int, int, android.graphics.Rect, int, int, android.graphics.Rect); method public static void applyDisplay(int, android.graphics.Rect, android.graphics.Rect); + method public static int getAbsoluteGravity(int, boolean); method public static boolean isHorizontal(int); method public static boolean isVertical(int); + field public static final int AFTER = 8388613; // 0x800005 field public static final int AXIS_CLIP = 8; // 0x8 field public static final int AXIS_PULL_AFTER = 4; // 0x4 field public static final int AXIS_PULL_BEFORE = 2; // 0x2 field public static final int AXIS_SPECIFIED = 1; // 0x1 field public static final int AXIS_X_SHIFT = 0; // 0x0 field public static final int AXIS_Y_SHIFT = 4; // 0x4 + field public static final int BEFORE = 8388611; // 0x800003 field public static final int BOTTOM = 80; // 0x50 field public static final int CENTER = 17; // 0x11 field public static final int CENTER_HORIZONTAL = 1; // 0x1 @@ -20158,6 +20166,8 @@ package android.view { field public static final int HORIZONTAL_GRAVITY_MASK = 7; // 0x7 field public static final int LEFT = 3; // 0x3 field public static final int NO_GRAVITY = 0; // 0x0 + field public static final int RELATIVE_HORIZONTAL_DIRECTION = 8388608; // 0x800000 + field public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = 8388615; // 0x800007 field public static final int RIGHT = 5; // 0x5 field public static final int TOP = 48; // 0x30 field public static final int VERTICAL_GRAVITY_MASK = 112; // 0x70 @@ -21136,7 +21146,7 @@ package android.view { method public void recycle(); } - public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback { + public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback2 android.view.KeyEvent.Callback { ctor public View(android.content.Context); ctor public View(android.content.Context, android.util.AttributeSet); ctor public View(android.content.Context, android.util.AttributeSet, int); @@ -21322,6 +21332,7 @@ package android.view { method public boolean isInTouchMode(); method public boolean isLayoutRequested(); method public boolean isLayoutRtl(); + method public boolean isLayoutRtl(android.graphics.drawable.Drawable); method public boolean isLongClickable(); method public boolean isOpaque(); method protected boolean isPaddingOffsetRequired(); diff --git a/core/java/android/view/Gravity.java b/core/java/android/view/Gravity.java index cf79638..176c487 100644 --- a/core/java/android/view/Gravity.java +++ b/core/java/android/view/Gravity.java @@ -80,9 +80,12 @@ public class Gravity /** Flag to clip the edges of the object to its container along the * horizontal axis. */ public static final int CLIP_HORIZONTAL = AXIS_CLIP<<AXIS_X_SHIFT; - + + /** Raw bit controlling whether the horizontal direction is relative (before/after) or not. */ + public static final int RELATIVE_HORIZONTAL_DIRECTION = 0x00800000; + /** - * Binary mask to get the horizontal gravity of a gravity. + * Binary mask to get the absolute horizontal gravity of a gravity. */ public static final int HORIZONTAL_GRAVITY_MASK = (AXIS_SPECIFIED | AXIS_PULL_BEFORE | AXIS_PULL_AFTER) << AXIS_X_SHIFT; @@ -106,8 +109,19 @@ public class Gravity */ public static final int DISPLAY_CLIP_HORIZONTAL = 0x01000000; + /** Push object to x-axis position before its container, not changing its size. */ + public static final int BEFORE = RELATIVE_HORIZONTAL_DIRECTION | LEFT; + + /** Push object to x-axis position after its container, not changing its size. */ + public static final int AFTER = RELATIVE_HORIZONTAL_DIRECTION | RIGHT; + /** - * Apply a gravity constant to an object. + * Binary mask for the horizontal gravity and script specific direction bit. + */ + public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = BEFORE | AFTER; + + /** + * Apply a gravity constant to an object. This suppose that the layout direction is LTR. * * @param gravity The desired placement of the object, as defined by the * constants in this class. @@ -119,12 +133,33 @@ public class Gravity * @param outRect Receives the computed frame of the object in its * container. */ - public static void apply(int gravity, int w, int h, Rect container, - Rect outRect) { + public static void apply(int gravity, int w, int h, Rect container, Rect outRect) { apply(gravity, w, h, container, 0, 0, outRect); } /** + * Apply a gravity constant to an object and take care if layout direction is RTL or not. + * + * @param gravity The desired placement of the object, as defined by the + * constants in this class. + * @param w The horizontal size of the object. + * @param h The vertical size of the object. + * @param container The frame of the containing space, in which the object + * will be placed. Should be large enough to contain the + * width and height of the object. + * @param outRect Receives the computed frame of the object in its + * container. + * @param isRtl Whether the layout is right-to-left. + * + * @hide + */ + public static void apply(int gravity, int w, int h, Rect container, + Rect outRect, boolean isRtl) { + int absGravity = getAbsoluteGravity(gravity, isRtl); + apply(absGravity, w, h, container, 0, 0, outRect); + } + + /** * Apply a gravity constant to an object. * * @param gravity The desired placement of the object, as defined by the @@ -146,7 +181,7 @@ public class Gravity * container. */ public static void apply(int gravity, int w, int h, Rect container, - int xAdj, int yAdj, Rect outRect) { + int xAdj, int yAdj, Rect outRect) { switch (gravity&((AXIS_PULL_BEFORE|AXIS_PULL_AFTER)<<AXIS_X_SHIFT)) { case 0: outRect.left = container.left @@ -301,6 +336,54 @@ public class Gravity * @return true if the supplied gravity has an horizontal pull */ public static boolean isHorizontal(int gravity) { - return gravity > 0 && (gravity & HORIZONTAL_GRAVITY_MASK) != 0; + return gravity > 0 && (gravity & RELATIVE_HORIZONTAL_GRAVITY_MASK) != 0; + } + + /** + * <p>Convert script specific gravity to absolute horizontal value.</p> + * + * if horizontal direction is LTR, then BEFORE will set LEFT and AFTER will set RIGHT. + * if horizontal direction is RTL, then BEFORE will set RIGHT and AFTER will set LEFT. + * + * If no horizontal direction is found, then just add LEFT to the existing gravity + * + * @param gravity The gravity to convert to absolute (horizontal) values. + * @param isRtl Whether the layout is right-to-left. + * @return gravity converted to absolute (horizontal) values. + */ + public static int getAbsoluteGravity(int gravity, boolean isRtl) { + int result = gravity; + // Set default gravity, if no horizontal gravity is specified + if ((result & HORIZONTAL_GRAVITY_MASK) == 0) { + result |= Gravity.LEFT; + } + // If layout is script specific and gravity is horizontal relative (BEFORE or AFTER) + if ((result & RELATIVE_HORIZONTAL_DIRECTION) > 0) { + if ((result & Gravity.BEFORE) == Gravity.BEFORE) { + // Remove the BEFORE bit + result &= ~BEFORE; + if (isRtl) { + // Set the RIGHT bit + result |= RIGHT; + } else { + // Set the LEFT bit + result |= LEFT; + } + } else if ((result & Gravity.AFTER) == Gravity.AFTER) { + // Remove the AFTER bit + result &= ~AFTER; + if (isRtl) { + // Set the LEFT bit + result |= LEFT; + } else { + // Set the RIGHT bit + result |= RIGHT; + } + } + // Don't need the script specific bit any more, so remove it as we are converting to + // absolute values (LEFT or RIGHT) + result &= ~RELATIVE_HORIZONTAL_DIRECTION; + } + return result; } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index e54046d..017e5e3 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -631,7 +631,7 @@ import java.util.concurrent.CopyOnWriteArrayList; * * @see android.view.ViewGroup */ -public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource { +public class View implements Drawable.Callback2, KeyEvent.Callback, AccessibilityEventSource { private static final boolean DBG = false; /** @@ -10238,6 +10238,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } } + /** + * Check if a given Drawable is in RTL layout direction. + * + * @param who the recipient of the action + */ + public boolean isLayoutRtl(Drawable who) { + return (who == mBGDrawable) && isLayoutRtl(); + } + /** * If your view subclass is displaying its own Drawable objects, it should * override this function and return true for any Drawable it is diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 9395d5c..a1ddd08 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -77,8 +77,8 @@ public interface WindowManager extends ViewManager { implements Parcelable { /** * X position for this window. With the default gravity it is ignored. - * When using {@link Gravity#LEFT} or {@link Gravity#RIGHT} it provides - * an offset from the given edge. + * When using {@link Gravity#LEFT} or {@link Gravity#BEFORE} or {@link Gravity#RIGHT} or + * {@link Gravity#AFTER} it provides an offset from the given edge. */ @ViewDebug.ExportedProperty public int x; diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java index 0659063..2a1398d 100644 --- a/core/java/android/widget/FrameLayout.java +++ b/core/java/android/widget/FrameLayout.java @@ -115,7 +115,7 @@ public class FrameLayout extends ViewGroup { } /** - * Describes how the foreground is positioned. Defaults to FILL. + * Describes how the foreground is positioned. Defaults to BEFORE and TOP. * * @param foregroundGravity See {@link android.view.Gravity} * @@ -124,8 +124,8 @@ public class FrameLayout extends ViewGroup { @android.view.RemotableViewMethod public void setForegroundGravity(int foregroundGravity) { if (mForegroundGravity != foregroundGravity) { - if ((foregroundGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) { - foregroundGravity |= Gravity.LEFT; + if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { + foregroundGravity |= Gravity.BEFORE; } if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { @@ -364,7 +364,7 @@ public class FrameLayout extends ViewGroup { gravity = DEFAULT_CHILD_GRAVITY; } - final int horizontalGravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK; + final int horizontalGravity = Gravity.getAbsoluteGravity(gravity, isLayoutRtl()); final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK; switch (horizontalGravity) { @@ -436,7 +436,7 @@ public class FrameLayout extends ViewGroup { } Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(), - foreground.getIntrinsicHeight(), selfBounds, overlayBounds); + foreground.getIntrinsicHeight(), selfBounds, overlayBounds, isLayoutRtl()); foreground.setBounds(overlayBounds); } diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index 0383b5c..732cedc 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -1408,19 +1408,20 @@ public class GridView extends AbsListView { int childLeft; final int childTop = flow ? y : y - h; - switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { - case Gravity.LEFT: - childLeft = childrenLeft; - break; - case Gravity.CENTER_HORIZONTAL: - childLeft = childrenLeft + ((mColumnWidth - w) / 2); - break; - case Gravity.RIGHT: - childLeft = childrenLeft + mColumnWidth - w; - break; - default: - childLeft = childrenLeft; - break; + final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity,isLayoutRtl()); + switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { + case Gravity.LEFT: + childLeft = childrenLeft; + break; + case Gravity.CENTER_HORIZONTAL: + childLeft = childrenLeft + ((mColumnWidth - w) / 2); + break; + case Gravity.RIGHT: + childLeft = childrenLeft + mColumnWidth - w; + break; + default: + childLeft = childrenLeft; + break; } if (needToMeasure) { diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index d8068f9..2a0a2f3 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -187,6 +187,11 @@ public class ImageView extends View { } @Override + public boolean isLayoutRtl(Drawable dr) { + return ((dr == mDrawable) && isLayoutRtl()) || super.isLayoutRtl(dr); + } + + @Override protected boolean onSetAlpha(int alpha) { if (getBackground() == null) { int scale = alpha + (alpha >> 7); diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java index 6f30452..8d449e0 100644 --- a/core/java/android/widget/LinearLayout.java +++ b/core/java/android/widget/LinearLayout.java @@ -110,6 +110,8 @@ public class LinearLayout extends ViewGroup { @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"), @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"), @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"), + @ViewDebug.IntToString(from = Gravity.BEFORE, to = "BEFORE"), + @ViewDebug.IntToString(from = Gravity.AFTER, to = "AFTER"), @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"), @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"), @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"), @@ -117,7 +119,7 @@ public class LinearLayout extends ViewGroup { @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"), @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL") }) - private int mGravity = Gravity.LEFT | Gravity.TOP; + private int mGravity = Gravity.BEFORE | Gravity.TOP; @ViewDebug.ExportedProperty(category = "measurement") private int mTotalLength; @@ -1394,7 +1396,7 @@ public class LinearLayout extends ViewGroup { final int count = getVirtualChildCount(); final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK; - final int minorGravity = mGravity & Gravity.HORIZONTAL_GRAVITY_MASK; + final int minorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK; switch (majorGravity) { case Gravity.BOTTOM: @@ -1428,7 +1430,7 @@ public class LinearLayout extends ViewGroup { if (gravity < 0) { gravity = minorGravity; } - + gravity = Gravity.getAbsoluteGravity(gravity, isLayoutRtl()); switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.CENTER_HORIZONTAL: childLeft = paddingLeft + ((childSpace - childWidth) / 2) @@ -1483,7 +1485,7 @@ public class LinearLayout extends ViewGroup { final int count = getVirtualChildCount(); - final int majorGravity = mGravity & Gravity.HORIZONTAL_GRAVITY_MASK; + final int majorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK; final int minorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK; final boolean baselineAligned = mBaselineAligned; @@ -1491,7 +1493,7 @@ public class LinearLayout extends ViewGroup { final int[] maxAscent = mMaxAscent; final int[] maxDescent = mMaxDescent; - switch (majorGravity) { + switch (Gravity.getAbsoluteGravity(majorGravity, isLayoutRtl())) { case Gravity.RIGHT: // mTotalLength contains the padding already childLeft = mPaddingLeft + mRight - mLeft - mTotalLength; @@ -1630,8 +1632,8 @@ public class LinearLayout extends ViewGroup { @android.view.RemotableViewMethod public void setGravity(int gravity) { if (mGravity != gravity) { - if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) { - gravity |= Gravity.LEFT; + if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { + gravity |= Gravity.BEFORE; } if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { @@ -1645,9 +1647,9 @@ public class LinearLayout extends ViewGroup { @android.view.RemotableViewMethod public void setHorizontalGravity(int horizontalGravity) { - final int gravity = horizontalGravity & Gravity.HORIZONTAL_GRAVITY_MASK; - if ((mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != gravity) { - mGravity = (mGravity & ~Gravity.HORIZONTAL_GRAVITY_MASK) | gravity; + final int gravity = horizontalGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK; + if ((mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) != gravity) { + mGravity = (mGravity & ~Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) | gravity; requestLayout(); } } @@ -1724,6 +1726,8 @@ public class LinearLayout extends ViewGroup { @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"), @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"), @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"), + @ViewDebug.IntToString(from = Gravity.BEFORE, to = "BEFORE"), + @ViewDebug.IntToString(from = Gravity.AFTER, to = "AFTER"), @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"), @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"), @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"), diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index 30374af..373a177 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -916,6 +916,12 @@ public class ProgressBar extends View { } @Override + public boolean isLayoutRtl(Drawable who) { + return ((who == mProgressDrawable || who == mIndeterminateDrawable) && isLayoutRtl()) || + super.isLayoutRtl(who); + } + + @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { updateDrawableBounds(w, h); } diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index 9069283..acd8539 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -16,32 +16,32 @@ package android.widget; -import com.android.internal.R; - import android.content.Context; -import android.content.res.TypedArray; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Rect; import android.util.AttributeSet; -import android.util.SparseArray; -import android.util.Poolable; import android.util.Pool; -import android.util.Pools; +import android.util.Poolable; import android.util.PoolableManager; -import static android.util.Log.d; +import android.util.Pools; +import android.util.SparseArray; import android.view.Gravity; import android.view.View; import android.view.ViewDebug; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.widget.RemoteViews.RemoteView; +import com.android.internal.R; +import java.util.ArrayList; import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedList; import java.util.SortedSet; import java.util.TreeSet; -import java.util.LinkedList; -import java.util.HashSet; -import java.util.ArrayList; + +import static android.util.Log.d; /** * A Layout where the positions of the children can be described in relation to each other or to the @@ -221,8 +221,8 @@ public class RelativeLayout extends ViewGroup { @android.view.RemotableViewMethod public void setGravity(int gravity) { if (mGravity != gravity) { - if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) { - gravity |= Gravity.LEFT; + if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { + gravity |= Gravity.BEFORE; } if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { @@ -236,9 +236,9 @@ public class RelativeLayout extends ViewGroup { @android.view.RemotableViewMethod public void setHorizontalGravity(int horizontalGravity) { - final int gravity = horizontalGravity & Gravity.HORIZONTAL_GRAVITY_MASK; - if ((mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != gravity) { - mGravity = (mGravity & ~Gravity.HORIZONTAL_GRAVITY_MASK) | gravity; + final int gravity = horizontalGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK; + if ((mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) != gravity) { + mGravity = (mGravity & ~Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) | gravity; requestLayout(); } } @@ -339,7 +339,7 @@ public class RelativeLayout extends ViewGroup { mHasBaselineAlignedChild = false; View ignore = null; - int gravity = mGravity & Gravity.HORIZONTAL_GRAVITY_MASK; + int gravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK; final boolean horizontalGravity = gravity != Gravity.LEFT && gravity != 0; gravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK; final boolean verticalGravity = gravity != Gravity.TOP && gravity != 0; @@ -494,7 +494,8 @@ public class RelativeLayout extends ViewGroup { height - mPaddingBottom); final Rect contentBounds = mContentBounds; - Gravity.apply(mGravity, right - left, bottom - top, selfBounds, contentBounds); + Gravity.apply(mGravity, right - left, bottom - top, selfBounds, contentBounds, + isLayoutRtl()); final int horizontalOffset = contentBounds.left - left; final int verticalOffset = contentBounds.top - top; diff --git a/core/java/android/widget/TableRow.java b/core/java/android/widget/TableRow.java index b612004..5f20c85 100644 --- a/core/java/android/widget/TableRow.java +++ b/core/java/android/widget/TableRow.java @@ -224,7 +224,8 @@ public class TableRow extends LinearLayout { final int childWidth = child.getMeasuredWidth(); lp.mOffset[LayoutParams.LOCATION_NEXT] = columnWidth - childWidth; - switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) { + final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, isLayoutRtl()); + switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: // don't offset on X axis break; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 67b99da..a73a6cf 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -2093,8 +2093,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @attr ref android.R.styleable#TextView_gravity */ public void setGravity(int gravity) { - if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) { - gravity |= Gravity.LEFT; + if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { + gravity |= Gravity.BEFORE; } if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { gravity |= Gravity.TOP; @@ -2102,8 +2102,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener boolean newLayout = false; - if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) != - (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK)) { + if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) != + (mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK)) { newLayout = true; } @@ -4142,6 +4142,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } @Override + public boolean isLayoutRtl(Drawable who) { + if (who == null) return false; + final TextView.Drawables drawables = mDrawables; + if (who == drawables.mDrawableLeft || who == drawables.mDrawableRight || + who == drawables.mDrawableTop || who == drawables.mDrawableBottom) { + return isLayoutRtl(); + } + return super.isLayoutRtl(who); + } + + @Override protected boolean onSetAlpha(int alpha) { // Alpha is supported if and only if the drawing can be done in one pass. // TODO text with spans with a background color currently do not respect this alpha. @@ -4380,9 +4391,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener canvas.translate(compoundPaddingLeft, extendedPaddingTop + voffsetText); } + final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, isLayoutRtl()); if (mEllipsize == TextUtils.TruncateAt.MARQUEE) { if (!mSingleLine && getLineCount() == 1 && canMarquee() && - (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) { + (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) { canvas.translate(mLayout.getLineRight(0) - (mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight()), 0.0f); } @@ -5528,7 +5540,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } Layout.Alignment alignment; - switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { + final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, isLayoutRtl()); + switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.CENTER_HORIZONTAL: alignment = Layout.Alignment.ALIGN_CENTER; break; @@ -7563,7 +7576,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return 0.0f; } } else if (getLineCount() == 1) { - switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { + final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, isLayoutRtl()); + switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: return 0.0f; case Gravity.RIGHT: @@ -7586,7 +7600,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final Marquee marquee = mMarquee; return (marquee.mMaxFadeScroll - marquee.mScroll) / getHorizontalFadingEdgeLength(); } else if (getLineCount() == 1) { - switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { + final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, isLayoutRtl()); + switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: final int textWidth = (mRight - mLeft) - getCompoundPaddingLeft() - getCompoundPaddingRight(); diff --git a/core/java/com/android/internal/view/menu/IconMenuItemView.java b/core/java/com/android/internal/view/menu/IconMenuItemView.java index afa8a01..c337a5d 100644 --- a/core/java/com/android/internal/view/menu/IconMenuItemView.java +++ b/core/java/com/android/internal/view/menu/IconMenuItemView.java @@ -282,7 +282,7 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie getLineBounds(0, tmpRect); mPositionIconAvailable.set(0, 0, getWidth(), tmpRect.top); Gravity.apply(Gravity.CENTER_VERTICAL | Gravity.LEFT, mIcon.getIntrinsicWidth(), mIcon - .getIntrinsicHeight(), mPositionIconAvailable, mPositionIconOutput); + .getIntrinsicHeight(), mPositionIconAvailable, mPositionIconOutput, isLayoutRtl()); mIcon.setBounds(mPositionIconOutput); } diff --git a/core/java/com/android/internal/widget/TextProgressBar.java b/core/java/com/android/internal/widget/TextProgressBar.java index aee7b76..e113dd8 100644 --- a/core/java/com/android/internal/widget/TextProgressBar.java +++ b/core/java/com/android/internal/widget/TextProgressBar.java @@ -86,7 +86,8 @@ public class TextProgressBar extends RelativeLayout implements OnChronometerTick // Check if Chronometer should move with with ProgressBar mChronometerFollow = (params.width == ViewGroup.LayoutParams.WRAP_CONTENT); - mChronometerGravity = (mChronometer.getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK); + mChronometerGravity = (mChronometer.getGravity() & + Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK); } else if (childId == PROGRESSBAR_ID && child instanceof ProgressBar) { mProgressBar = (ProgressBar) child; diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index f854e93..b82a2d2 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1128,6 +1128,10 @@ The clip will be based on the horizontal gravity: a left gravity will clip the right edge, a right gravity will clip the left edge, and neither will clip both edges. --> <flag name="clip_horizontal" value="0x08" /> + <!-- Push object to the beginning of its container, not changing its size. --> + <flag name="before" value="0x00800003" /> + <!-- Push object to the end of its container, not changing its size. --> + <flag name="after" value="0x00800005" /> </attr> <!-- Controls whether links such as urls and email addresses are @@ -1184,6 +1188,10 @@ The clip will be based on the horizontal gravity: a left gravity will clip the right edge, a right gravity will clip the left edge, and neither will clip both edges. --> <flag name="clip_horizontal" value="0x08" /> + <!-- Push object to the beginning of its container, not changing its size. --> + <flag name="before" value="0x00800003" /> + <!-- Push object to the end of its container, not changing its size. --> + <flag name="after" value="0x00800005" /> </attr> <!-- Standard orientation constant. --> diff --git a/core/tests/coretests/src/android/view/GravityTest.java b/core/tests/coretests/src/android/view/GravityTest.java new file mode 100644 index 0000000..010127f --- /dev/null +++ b/core/tests/coretests/src/android/view/GravityTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2011 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. + */ + +package android.view; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +public class GravityTest extends AndroidTestCase { + + @SmallTest + public void testGetAbsoluteGravity() throws Exception { + assertOneGravity(Gravity.LEFT, Gravity.LEFT, false); + assertOneGravity(Gravity.LEFT, Gravity.LEFT, true); + + assertOneGravity(Gravity.RIGHT, Gravity.RIGHT, false); + assertOneGravity(Gravity.RIGHT, Gravity.RIGHT, true); + + assertOneGravity(Gravity.TOP|Gravity.LEFT, Gravity.TOP, false); + assertOneGravity(Gravity.TOP|Gravity.LEFT, Gravity.TOP, true); + + assertOneGravity(Gravity.BOTTOM|Gravity.LEFT, Gravity.BOTTOM, false); + assertOneGravity(Gravity.BOTTOM|Gravity.LEFT, Gravity.BOTTOM, true); + + assertOneGravity(Gravity.CENTER_VERTICAL|Gravity.LEFT, Gravity.CENTER_VERTICAL, false); + assertOneGravity(Gravity.CENTER_VERTICAL|Gravity.LEFT, Gravity.CENTER_VERTICAL, true); + + assertOneGravity(Gravity.CENTER_HORIZONTAL, Gravity.CENTER_HORIZONTAL, false); + assertOneGravity(Gravity.CENTER_HORIZONTAL, Gravity.CENTER_HORIZONTAL, true); + + assertOneGravity(Gravity.CENTER, Gravity.CENTER, false); + assertOneGravity(Gravity.CENTER, Gravity.CENTER, true); + + assertOneGravity(Gravity.FILL_VERTICAL|Gravity.LEFT, Gravity.FILL_VERTICAL, false); + assertOneGravity(Gravity.FILL_VERTICAL|Gravity.LEFT, Gravity.FILL_VERTICAL, true); + + assertOneGravity(Gravity.FILL_HORIZONTAL, Gravity.FILL_HORIZONTAL, false); + assertOneGravity(Gravity.FILL_HORIZONTAL, Gravity.FILL_HORIZONTAL, true); + + assertOneGravity(Gravity.FILL, Gravity.FILL, false); + assertOneGravity(Gravity.FILL, Gravity.FILL, true); + + assertOneGravity(Gravity.CLIP_HORIZONTAL|Gravity.LEFT, Gravity.CLIP_HORIZONTAL, false); + assertOneGravity(Gravity.CLIP_HORIZONTAL|Gravity.LEFT, Gravity.CLIP_HORIZONTAL, true); + + assertOneGravity(Gravity.CLIP_VERTICAL|Gravity.LEFT, Gravity.CLIP_VERTICAL, false); + assertOneGravity(Gravity.CLIP_VERTICAL|Gravity.LEFT, Gravity.CLIP_VERTICAL, true); + + assertOneGravity(Gravity.LEFT, Gravity.BEFORE, false); + assertOneGravity(Gravity.RIGHT, Gravity.BEFORE, true); + + assertOneGravity(Gravity.RIGHT, Gravity.AFTER, false); + assertOneGravity(Gravity.LEFT, Gravity.AFTER, true); + } + + private void assertOneGravity(int expected, int initial, boolean isRtl) { + assertEquals(expected, Gravity.getAbsoluteGravity(initial, isRtl)); + } +} diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index c9c9fd7..311f024 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -387,7 +387,7 @@ public class BitmapDrawable extends Drawable { if (shader == null) { if (mApplyGravity) { Gravity.apply(state.mGravity, mBitmapWidth, mBitmapHeight, - getBounds(), mDstRect); + getBounds(), mDstRect, isLayoutRtlSelf()); mApplyGravity = false; } canvas.drawBitmap(bitmap, null, mDstRect, state.mPaint); diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java index b333e01..83020aa 100644 --- a/graphics/java/android/graphics/drawable/ClipDrawable.java +++ b/graphics/java/android/graphics/drawable/ClipDrawable.java @@ -209,7 +209,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { if ((mClipState.mOrientation & VERTICAL) != 0) { h -= (h - ih) * (10000 - level) / 10000; } - Gravity.apply(mClipState.mGravity, w, h, bounds, r); + Gravity.apply(mClipState.mGravity, w, h, bounds, r, isLayoutRtlSelf()); if (w > 0 && h > 0) { canvas.save(); diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 159f371e..8994efc 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -288,6 +288,18 @@ public abstract class Drawable { } /** + * Implement this interface if you want to create an drawable that is RTL aware + */ + public static interface Callback2 extends Callback { + /** + * A Drawable can call this to know whether the <var>who</var> is in RTL layout direction. + * + * @param who The drawable being unscheduled. + */ + public boolean isLayoutRtl(Drawable who); + } + + /** * Bind a {@link Callback} object to this Drawable. Required for clients * that want to support animated drawables. * @@ -364,6 +376,18 @@ public abstract class Drawable { } /** + * Use the current {@link android.graphics.drawable.Drawable.Callback2} implementation to know + * if this Drawable is having a layout in RTL direction. + */ + public boolean isLayoutRtlSelf() { + final Callback callback = getCallback(); + if (callback == null || !(callback instanceof Callback2)) { + return false; + } + return ((Callback2) callback).isLayoutRtl(this); + } + + /** * Specify an alpha value for the drawable. 0 means fully transparent, and * 255 means fully opaque. */ diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java index a7ed0d0..cbe1f2d 100644 --- a/graphics/java/android/graphics/drawable/ScaleDrawable.java +++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java @@ -221,7 +221,7 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { final int ih = min ? mScaleState.mDrawable.getIntrinsicHeight() : 0; h -= (int) ((h - ih) * (10000 - level) * mScaleState.mScaleHeight / 10000); } - Gravity.apply(mScaleState.mGravity, w, h, bounds, r); + Gravity.apply(mScaleState.mGravity, w, h, bounds, r, isLayoutRtlSelf()); if (w > 0 && h > 0) { mScaleState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom); |