Fix bug #6427629 Clean up layout direction APIs

- getLayoutDirection() / getTextDirection() / getTextAligment() dont do resolution
- resolution done into onMeasure()
- use XX_RESOLVED bits to check if resolution needs to be done
- code formatting

Change-Id: Ie46a5535860e90f3449b96cfe0aa04dd7e3006d7
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0f58300..feec464 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2141,6 +2141,17 @@
      */
     static final int PFLAG2_PADDING_RESOLVED = 0x20000000;
 
+    /**
+     * Flag indicating that the start/end drawables has been resolved into left/right ones.
+     */
+    static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000;
+
+    /**
+     * Group of bits indicating that RTL properties resolution is done.
+     */
+    static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED |
+            PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED;
+
     // There are a couple of flags left in mPrivateFlags2
 
     /* End of masks for mPrivateFlags2 */
@@ -3199,9 +3210,12 @@
         mResources = context != null ? context.getResources() : null;
         mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED;
         // Set layout and text direction defaults
-        mPrivateFlags2 = (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) |
+        mPrivateFlags2 =
+                (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) |
                 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) |
+                (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) |
                 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) |
+                (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) |
                 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT);
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
         setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
@@ -3419,7 +3433,8 @@
                     break;
                 case com.android.internal.R.styleable.View_layoutDirection:
                     // Clear any layout direction flags (included resolved bits) already set
-                    mPrivateFlags2 &= ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK);
+                    mPrivateFlags2 &=
+                            ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK);
                     // Set the layout direction flags depending on the value of the attribute
                     final int layoutDirection = a.getInt(attr, -1);
                     final int value = (layoutDirection != -1) ?
@@ -5771,6 +5786,8 @@
      *   {@link #LAYOUT_DIRECTION_INHERIT} or
      *   {@link #LAYOUT_DIRECTION_LOCALE}.
      * @attr ref android.R.styleable#View_layoutDirection
+     *
+     * @hide
      */
     @ViewDebug.ExportedProperty(category = "layout", mapping = {
         @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR,     to = "LTR"),
@@ -5778,7 +5795,7 @@
         @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"),
         @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE,  to = "LOCALE")
     })
-    private int getRawLayoutDirection() {
+    public int getRawLayoutDirection() {
         return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT;
     }
 
@@ -5786,10 +5803,16 @@
      * Set the layout direction for this view. This will propagate a reset of layout direction
      * resolution to the view's children and resolve layout direction for this view.
      *
-     * @param layoutDirection One of {@link #LAYOUT_DIRECTION_LTR},
-     *   {@link #LAYOUT_DIRECTION_RTL},
-     *   {@link #LAYOUT_DIRECTION_INHERIT} or
-     *   {@link #LAYOUT_DIRECTION_LOCALE}.
+     * @param layoutDirection the layout direction to set. Should be one of:
+     *
+     * {@link #LAYOUT_DIRECTION_LTR},
+     * {@link #LAYOUT_DIRECTION_RTL},
+     * {@link #LAYOUT_DIRECTION_INHERIT},
+     * {@link #LAYOUT_DIRECTION_LOCALE}.
+     *
+     * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution
+     * proceeds up the parent chain of the view to get the value. If there is no parent, then it
+     * will return the default {@link #LAYOUT_DIRECTION_LTR}.
      *
      * @attr ref android.R.styleable#View_layoutDirection
      */
@@ -5802,11 +5825,8 @@
             // Set the new layout direction (filtered)
             mPrivateFlags2 |=
                     ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK);
-            resolveRtlProperties();
-            // Notify changes
-            onRtlPropertiesChanged();
-            // ... and ask for a layout pass
-            requestLayout();
+            // We need to resolve all RTL properties as they all depend on layout direction
+            resolveRtlPropertiesIfNeeded();
         }
     }
 
@@ -5815,6 +5835,9 @@
      *
      * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns
      * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL.
+     *
+     * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version
+     * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}.
      */
     @ViewDebug.ExportedProperty(category = "layout", mapping = {
         @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"),
@@ -5826,12 +5849,8 @@
             mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED;
             return LAYOUT_DIRECTION_LTR;
         }
-        // The layout direction will be resolved only if needed
-        if ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) != PFLAG2_LAYOUT_DIRECTION_RESOLVED) {
-            resolveLayoutDirection();
-        }
-        return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ?
-                LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR;
+        return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ==
+                PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR;
     }
 
     /**
@@ -11473,10 +11492,6 @@
 
         jumpDrawablesToCurrentState();
 
-        resolveRtlProperties();
-        // Notify changes
-        onRtlPropertiesChanged();
-
         clearAccessibilityFocus();
         if (isFocused()) {
             InputMethodManager imm = InputMethodManager.peekInstance();
@@ -11489,25 +11504,41 @@
     }
 
     /**
-     * Resolve all RTL related properties
+     * Resolve all RTL related properties.
      */
-    void resolveRtlProperties() {
-        // Order is important here: LayoutDirection MUST be resolved first...
-        resolveLayoutDirection();
+    void resolveRtlPropertiesIfNeeded() {
+        if (!needRtlPropertiesResolution()) return;
+
+        // Order is important here: LayoutDirection MUST be resolved first
+        if (!isLayoutDirectionResolved()) {
+            resolveLayoutDirection();
+            resolveLayoutParams();
+        }
         // ... then we can resolve the others properties depending on the resolved LayoutDirection.
-        resolveTextDirection();
-        resolveTextAlignment();
-        resolvePadding();
-        resolveLayoutParams();
-        resolveDrawables();
+        if (!isTextDirectionResolved()) {
+            resolveTextDirection();
+        }
+        if (!isTextAlignmentResolved()) {
+            resolveTextAlignment();
+        }
+        if (!isPaddingResolved()) {
+            resolvePadding();
+        }
+        if (!isDrawablesResolved()) {
+            resolveDrawables();
+        }
+        requestLayout();
+        invalidate(true);
+        onRtlPropertiesChanged();
     }
 
-    // Reset resolution of all RTL related properties
+    // Reset resolution of all RTL related properties.
     void resetRtlProperties() {
         resetResolvedLayoutDirection();
         resetResolvedTextDirection();
         resetResolvedTextAlignment();
         resetResolvedPadding();
+        resetResolvedDrawables();
     }
 
     /**
@@ -11537,6 +11568,13 @@
     }
 
     /**
+     * @return true if RTL properties need resolution.
+     */
+    private boolean needRtlPropertiesResolution() {
+        return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED;
+    }
+
+    /**
      * Called when any RTL property (layout direction or text direction or text alignment) has
      * been changed.
      *
@@ -11613,7 +11651,8 @@
     }
 
     /**
-     * Reset the resolved layout direction.
+     * Reset the resolved layout direction. Layout direction will be resolved during a call to
+     * {@link #onMeasure(int, int)}.
      *
      * @hide
      */
@@ -11623,6 +11662,8 @@
     }
 
     /**
+     * @return true if the layout direction is inherited.
+     *
      * @hide
      */
     public boolean isLayoutDirectionInherited() {
@@ -11630,12 +11671,19 @@
     }
 
     /**
+     * @return true if layout direction has been resolved.
+     */
+    private boolean isLayoutDirectionResolved() {
+        return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED;
+    }
+
+    /**
      * Return if padding has been resolved
      *
      * @hide
      */
     boolean isPaddingResolved() {
-        return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) != 0;
+        return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED;
     }
 
     /**
@@ -14112,6 +14160,7 @@
         if (mBackground != null) {
             mBackground.setLayoutDirection(getLayoutDirection());
         }
+        mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED;
         onResolveDrawables(getLayoutDirection());
     }
 
@@ -14130,6 +14179,14 @@
     public void onResolveDrawables(int layoutDirection) {
     }
 
+    private void resetResolvedDrawables() {
+        mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED;
+    }
+
+    private boolean isDrawablesResolved() {
+        return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED;
+    }
+
     /**
      * If your view subclass is displaying its own Drawable objects, it should
      * override this function and return true for any Drawable it is
@@ -14399,6 +14456,7 @@
                 padding = new Rect();
                 sThreadLocal.set(padding);
             }
+            resetResolvedDrawables();
             background.setLayoutDirection(getLayoutDirection());
             if (background.getPadding(padding)) {
                 resetResolvedPadding();
@@ -15375,9 +15433,7 @@
             // first clears the measured dimension flag
             mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
 
-            if (!isPaddingResolved()) {
-                resolvePadding();
-            }
+            resolveRtlPropertiesIfNeeded();
 
             // measure ourselves, this should set the measured dimension flag back
             onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -16522,6 +16578,10 @@
      * {@link #TEXT_DIRECTION_LTR},
      * {@link #TEXT_DIRECTION_RTL},
      * {@link #TEXT_DIRECTION_LOCALE}
+     *
+     * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution
+     * proceeds up the parent chain of the view to get the value. If there is no parent, then it will
+     * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}.
      */
     public void setTextDirection(int textDirection) {
         if (getRawTextDirection() != textDirection) {
@@ -16530,6 +16590,8 @@
             resetResolvedTextDirection();
             // Set the new text direction
             mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK);
+            // Do resolution
+            resolveTextDirection();
             // Notify change
             onRtlPropertiesChanged();
             // Refresh
@@ -16541,11 +16603,6 @@
     /**
      * Return the resolved text direction.
      *
-     * This needs resolution if the value is TEXT_DIRECTION_INHERIT. The resolution matches what has
-     * been set by {@link #setTextDirection(int)} if it is not TEXT_DIRECTION_INHERIT, otherwise the
-     * resolution proceeds up the parent chain of the view. If there is no parent, then it will
-     * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}.
-     *
      * @return the resolved text direction. Returns one of:
      *
      * {@link #TEXT_DIRECTION_FIRST_STRONG}
@@ -16555,10 +16612,6 @@
      * {@link #TEXT_DIRECTION_LOCALE}
      */
     public int getTextDirection() {
-        // The text direction will be resolved only if needed
-        if ((mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) != PFLAG2_TEXT_DIRECTION_RESOLVED) {
-            resolveTextDirection();
-        }
         return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
     }
 
@@ -16597,6 +16650,8 @@
                     } else {
                         // 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;
                     }
                     break;
                 case TEXT_DIRECTION_FIRST_STRONG:
@@ -16635,16 +16690,21 @@
     }
 
     /**
-     * Reset resolved text direction. Text direction can be resolved with a call to
-     * getTextDirection().
+     * Reset resolved text direction. Text direction will be resolved during a call to
+     * {@link #onMeasure(int, int)}.
      *
      * @hide
      */
     public void resetResolvedTextDirection() {
+        // Reset any previous text direction resolution
         mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK);
+        // Set to default value
+        mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
     }
 
     /**
+     * @return true if text direction is inherited.
+     *
      * @hide
      */
     public boolean isTextDirectionInherited() {
@@ -16652,6 +16712,13 @@
     }
 
     /**
+     * @return true if text direction is resolved.
+     */
+    private boolean isTextDirectionResolved() {
+        return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED;
+    }
+
+    /**
      * Return the value specifying the text alignment or policy that was set with
      * {@link #setTextAlignment(int)}.
      *
@@ -16693,6 +16760,10 @@
      * {@link #TEXT_ALIGNMENT_VIEW_START},
      * {@link #TEXT_ALIGNMENT_VIEW_END}
      *
+     * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution
+     * proceeds up the parent chain of the view to get the value. If there is no parent, then it
+     * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}.
+     *
      * @attr ref android.R.styleable#View_textAlignment
      */
     public void setTextAlignment(int textAlignment) {
@@ -16701,7 +16772,10 @@
             mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK;
             resetResolvedTextAlignment();
             // Set the new text alignment
-            mPrivateFlags2 |= ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK);
+            mPrivateFlags2 |=
+                    ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK);
+            // Do resolution
+            resolveTextAlignment();
             // Notify change
             onRtlPropertiesChanged();
             // Refresh
@@ -16713,10 +16787,6 @@
     /**
      * Return the resolved text alignment.
      *
-     * The resolved text alignment. This needs resolution if the value is
-     * TEXT_ALIGNMENT_INHERIT. The resolution matches {@link #setTextAlignment(int)}  if it is
-     * not TEXT_ALIGNMENT_INHERIT, otherwise resolution proceeds up the parent chain of the view.
-     *
      * @return the resolved text alignment. Returns one of:
      *
      * {@link #TEXT_ALIGNMENT_GRAVITY},
@@ -16736,11 +16806,8 @@
             @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END")
     })
     public int getTextAlignment() {
-        // If text alignment is not resolved, then resolve it
-        if ((mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) != PFLAG2_TEXT_ALIGNMENT_RESOLVED) {
-            resolveTextAlignment();
-        }
-        return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
+        return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >>
+                PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
     }
 
     /**
@@ -16782,6 +16849,8 @@
                     else {
                         // 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;
                     }
                     break;
                 case TEXT_ALIGNMENT_GRAVITY:
@@ -16821,16 +16890,21 @@
     }
 
     /**
-     * Reset resolved text alignment.
+     * Reset resolved text alignment. Text alignment will be resolved during a call to
+     * {@link #onMeasure(int, int)}.
      *
      * @hide
      */
     public void resetResolvedTextAlignment() {
         // Reset any previous text alignment resolution
         mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK);
+        // Set to default
+        mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
     }
 
     /**
+     * @return true if text alignment is inherited.
+     *
      * @hide
      */
     public boolean isTextAlignmentInherited() {
@@ -16838,6 +16912,13 @@
     }
 
     /**
+     * @return true if text alignment is resolved.
+     */
+    private boolean isTextAlignmentResolved() {
+        return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED;
+    }
+
+    /**
      * Generate a value suitable for use in {@link #setId(int)}.
      * This value will not collide with ID values generated at build time by aapt for R.id.
      *