Add View.getResolvedLayoutDirection()

- update Callback2 interface
- update Gravity.getAbsoluteGravity() and Gravity.apply() to be more generic
 by changing "boolean isRtl" parameter to "int layoutDirection"
- fix BiDiTests for RTL FrameLayout

Change-Id: I97bb456c22d5fd3ecb34f08564ce4dbed37e7459
diff --git a/core/java/android/view/Gravity.java b/core/java/android/view/Gravity.java
index 69e6489..63f5ec1 100644
--- a/core/java/android/view/Gravity.java
+++ b/core/java/android/view/Gravity.java
@@ -151,13 +151,13 @@
      *                  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.
+     * @param layoutDirection The layout direction.
      *
      * @hide
      */
     public static void apply(int gravity, int w, int h, Rect container,
-            Rect outRect, boolean isRtl) {
-        int absGravity = getAbsoluteGravity(gravity, isRtl);
+            Rect outRect, int layoutDirection) {
+        int absGravity = getAbsoluteGravity(gravity, layoutDirection);
         apply(absGravity, w, h, container, 0, 0, outRect);
     }
 
@@ -347,18 +347,19 @@
      * if horizontal direction is LTR, then START will set LEFT and END will set RIGHT.
      * if horizontal direction is RTL, then START will set RIGHT and END will set LEFT.
      *
+     *
      * @param gravity The gravity to convert to absolute (horizontal) values.
-     * @param isRtl Whether the layout is right-to-left.
+     * @param layoutDirection The layout direction.
      * @return gravity converted to absolute (horizontal) values.
      */
-    public static int getAbsoluteGravity(int gravity, boolean isRtl) {
+    public static int getAbsoluteGravity(int gravity, int layoutDirection) {
         int result = gravity;
         // If layout is script specific and gravity is horizontal relative (START or END)
         if ((result & RELATIVE_LAYOUT_DIRECTION) > 0) {
             if ((result & Gravity.START) == Gravity.START) {
                 // Remove the START bit
                 result &= ~START;
-                if (isRtl) {
+                if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
                     // Set the RIGHT bit
                     result |= RIGHT;
                 } else {
@@ -368,7 +369,7 @@
             } else if ((result & Gravity.END) == Gravity.END) {
                 // Remove the END bit
                 result &= ~END;
-                if (isRtl) {
+                if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
                     // Set the LEFT bit
                     result |= LEFT;
                 } else {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 071905c..1dfb858 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4272,6 +4272,7 @@
      *   {@link #LAYOUT_DIRECTION_INHERIT} or
      *   {@link #LAYOUT_DIRECTION_LOCALE}.
      * @attr ref android.R.styleable#View_layoutDirection
+     *
      * @hide
      */
     @ViewDebug.ExportedProperty(category = "layout", mapping = {
@@ -4292,6 +4293,7 @@
      *   {@link #LAYOUT_DIRECTION_INHERIT} or
      *   {@link #LAYOUT_DIRECTION_LOCALE}.
      * @attr ref android.R.styleable#View_layoutDirection
+     *
      * @hide
      */
     @RemotableViewMethod
@@ -4300,6 +4302,37 @@
     }
 
     /**
+     * Returns the resolved layout direction for this view.
+     *
+     * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns
+     * {@link #LAYOUT_DIRECTION_LTR} id the layout direction is not RTL.
+     *
+     * @hide
+     */
+    @ViewDebug.ExportedProperty(category = "layout", mapping = {
+        @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR,     to = "RESOLVED_DIRECTION_LTR"),
+        @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL,     to = "RESOLVED_DIRECTION_RTL")
+    })
+    public int getResolvedLayoutDirection() {
+        resolveLayoutDirection();
+        return ((mPrivateFlags2 & RESOLVED_LAYOUT_RTL) == RESOLVED_LAYOUT_RTL) ?
+                LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR;
+    }
+
+    /**
+     * <p>Indicates whether or not this view's layout is right-to-left. This is resolved from
+     * layout attribute and/or the inherited value from the parent.</p>
+     *
+     * @return true if the layout is right-to-left.
+     *
+     * @hide
+     */
+    @ViewDebug.ExportedProperty(category = "layout")
+    public boolean isLayoutRtl() {
+        return (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL);
+    }
+
+    /**
      * If this view doesn't do any drawing on its own, set this flag to
      * allow further optimizations. By default, this flag is not set on
      * View, but could be set on some View subclasses such as ViewGroup.
@@ -8713,8 +8746,9 @@
         switch (getLayoutDirection()) {
             case LAYOUT_DIRECTION_INHERIT:
                 // If this is root view, no need to look at parent's layout dir.
-                if (mParent != null && mParent instanceof ViewGroup &&
-                        ((ViewGroup) mParent).isLayoutRtl()) {
+                if (mParent != null &&
+                        mParent instanceof ViewGroup &&
+                        ((ViewGroup) mParent).getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) {
                     mPrivateFlags2 |= RESOLVED_LAYOUT_RTL;
                 }
                 break;
@@ -10237,17 +10271,6 @@
     }
 
     /**
-     * <p>Indicates whether or not this view's layout is right-to-left. This is resolved from
-     * layout attribute and/or the inherited value from the parent.</p>
-     *
-     * @return true if the layout is right-to-left.
-     */
-    @ViewDebug.ExportedProperty(category = "layout")
-    public boolean isLayoutRtl() {
-        return (mPrivateFlags2 & RESOLVED_LAYOUT_RTL) == RESOLVED_LAYOUT_RTL;
-    }
-
-    /**
      * Assign a size and position to a view and all of its
      * descendants
      *
@@ -10459,13 +10482,15 @@
         }
     }
 
-     /**
-     * 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();
+    /**
+    * Return the layout direction of a given Drawable.
+    *
+    * @param who the Drawable to query
+    *
+    * @hide
+    */
+    public int getResolvedLayoutDirection(Drawable who) {
+        return (who == mBGDrawable) ? getResolvedLayoutDirection() : LAYOUT_DIRECTION_DEFAULT;
     }
 
     /**
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 6b498fe..5eba1a0 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -364,7 +364,8 @@
                     gravity = DEFAULT_CHILD_GRAVITY;
                 }
 
-                final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, isLayoutRtl());
+                final int layoutDirection = getResolvedLayoutDirection();
+                final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
                 final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
 
                 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
@@ -435,8 +436,10 @@
                     selfBounds.set(mPaddingLeft, mPaddingTop, w - mPaddingRight, h - mPaddingBottom);
                 }
 
+                final int layoutDirection = getResolvedLayoutDirection();
                 Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
-                        foreground.getIntrinsicHeight(), selfBounds, overlayBounds, isLayoutRtl());
+                        foreground.getIntrinsicHeight(), selfBounds, overlayBounds,
+                        layoutDirection);
                 foreground.setBounds(overlayBounds);
             }
             
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 732cedc..5d406de 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1408,7 +1408,8 @@
         int childLeft;
         final int childTop = flow ? y : y - h;
 
-        final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity,isLayoutRtl());
+        final int layoutDirection = getResolvedLayoutDirection();
+        final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
         switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
             case Gravity.LEFT:
                 childLeft = childrenLeft;
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 4b870ec..161b404 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -186,9 +186,13 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @Override
-    public boolean isLayoutRtl(Drawable dr) {
-        return (dr == mDrawable) ? isLayoutRtl() : super.isLayoutRtl(dr);
+    public int getResolvedLayoutDirection(Drawable dr) {
+        return (dr == mDrawable) ?
+                getResolvedLayoutDirection() : super.getResolvedLayoutDirection(dr);
     }
 
     @Override
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 0cdbc5b..e3bc946 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -1446,7 +1446,8 @@
                 if (gravity < 0) {
                     gravity = minorGravity;
                 }
-                final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, isLayoutRtl());
+                final int layoutDirection = getResolvedLayoutDirection();
+                final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
                 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
                     case Gravity.CENTER_HORIZONTAL:
                         childLeft = paddingLeft + ((childSpace - childWidth) / 2)
@@ -1509,7 +1510,8 @@
         final int[] maxAscent = mMaxAscent;
         final int[] maxDescent = mMaxDescent;
 
-        switch (Gravity.getAbsoluteGravity(majorGravity, isLayoutRtl())) {
+        final int layoutDirection = getResolvedLayoutDirection();
+        switch (Gravity.getAbsoluteGravity(majorGravity, layoutDirection)) {
             case Gravity.RIGHT:
                 // mTotalLength contains the padding already
                 childLeft = mPaddingLeft + mRight - mLeft - mTotalLength;
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index ed9114a..b2c3051 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -915,10 +915,13 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @Override
-    public boolean isLayoutRtl(Drawable who) {
+    public int getResolvedLayoutDirection(Drawable who) {
         return (who == mProgressDrawable || who == mIndeterminateDrawable) ?
-            isLayoutRtl() : super.isLayoutRtl(who);
+            getResolvedLayoutDirection() : super.getResolvedLayoutDirection(who);
     }
 
     @Override
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index a4771d5..a5cf62e 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -495,8 +495,9 @@
                     height - mPaddingBottom);
 
             final Rect contentBounds = mContentBounds;
+            final int layoutDirection = getResolvedLayoutDirection();
             Gravity.apply(mGravity, right - left, bottom - top, selfBounds, contentBounds,
-                    isLayoutRtl());
+                    layoutDirection);
 
             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 5f20c85..3fd4631 100644
--- a/core/java/android/widget/TableRow.java
+++ b/core/java/android/widget/TableRow.java
@@ -224,7 +224,8 @@
                 final int childWidth = child.getMeasuredWidth();
                 lp.mOffset[LayoutParams.LOCATION_NEXT] = columnWidth - childWidth;
 
-                final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, isLayoutRtl());
+                final int layoutDirection = getResolvedLayoutDirection();
+                final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
                 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
                     case Gravity.LEFT:
                         // don't offset on X axis
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9a5977a..470a23d6 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4145,17 +4145,20 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @Override
-    public boolean isLayoutRtl(Drawable who) {
-        if (who == null) return false;
+    public int getResolvedLayoutDirection(Drawable who) {
+        if (who == null) return View.LAYOUT_DIRECTION_LTR;
         if (mDrawables != null) {
             final Drawables drawables = mDrawables;
             if (who == drawables.mDrawableLeft || who == drawables.mDrawableRight ||
                 who == drawables.mDrawableTop || who == drawables.mDrawableBottom) {
-                return isLayoutRtl();
+                return getResolvedLayoutDirection();
             }
         }
-        return super.isLayoutRtl(who);
+        return super.getResolvedLayoutDirection(who);
     }
 
     @Override
@@ -4397,7 +4400,8 @@
             canvas.translate(compoundPaddingLeft, extendedPaddingTop + voffsetText);
         }
 
-        final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, isLayoutRtl());
+        final int layoutDirection = getResolvedLayoutDirection();
+        final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
         if (mEllipsize == TextUtils.TruncateAt.MARQUEE) {
             if (!mSingleLine && getLineCount() == 1 && canMarquee() &&
                     (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) {
@@ -5545,8 +5549,10 @@
             hintWidth = 0;
         }
 
+        final int layoutDirection = getResolvedLayoutDirection();
+        final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
+
         Layout.Alignment alignment;
-        final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, isLayoutRtl());
         switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
             case Gravity.CENTER_HORIZONTAL:
                 alignment = Layout.Alignment.ALIGN_CENTER;
@@ -7582,7 +7588,8 @@
                     return 0.0f;
                 }
             } else if (getLineCount() == 1) {
-                final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, isLayoutRtl());
+                final int layoutDirection = getResolvedLayoutDirection();
+                final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
                 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
                     case Gravity.LEFT:
                         return 0.0f;
@@ -7606,7 +7613,8 @@
                 final Marquee marquee = mMarquee;
                 return (marquee.mMaxFadeScroll - marquee.mScroll) / getHorizontalFadingEdgeLength();
             } else if (getLineCount() == 1) {
-                final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, isLayoutRtl());
+                final int layoutDirection = getResolvedLayoutDirection();
+                final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
                 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
                     case Gravity.LEFT:
                         final int textWidth = (mRight - mLeft) - getCompoundPaddingLeft() -
diff --git a/core/java/com/android/internal/view/menu/IconMenuItemView.java b/core/java/com/android/internal/view/menu/IconMenuItemView.java
index c337a5d..a743cfa 100644
--- a/core/java/com/android/internal/view/menu/IconMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuItemView.java
@@ -281,8 +281,10 @@
         Rect tmpRect = mPositionIconOutput;
         getLineBounds(0, tmpRect);
         mPositionIconAvailable.set(0, 0, getWidth(), tmpRect.top);
+        final int layoutDirection = getResolvedLayoutDirection();
         Gravity.apply(Gravity.CENTER_VERTICAL | Gravity.LEFT, mIcon.getIntrinsicWidth(), mIcon
-                .getIntrinsicHeight(), mPositionIconAvailable, mPositionIconOutput, isLayoutRtl());
+                .getIntrinsicHeight(), mPositionIconAvailable, mPositionIconOutput,
+                layoutDirection);
         mIcon.setBounds(mPositionIconOutput);
     }
 
diff --git a/core/tests/coretests/src/android/view/GravityTest.java b/core/tests/coretests/src/android/view/GravityTest.java
index 2a7a64f..d8ef650 100644
--- a/core/tests/coretests/src/android/view/GravityTest.java
+++ b/core/tests/coretests/src/android/view/GravityTest.java
@@ -67,6 +67,8 @@
     }
 
     private void assertOneGravity(int expected, int initial, boolean isRtl) {
-        assertEquals(expected, Gravity.getAbsoluteGravity(initial, isRtl));
+        final int layoutDirection = isRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
+
+        assertEquals(expected, Gravity.getAbsoluteGravity(initial, layoutDirection));
     }
 }