Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c44d880c authored by Fabrice Di Meglio's avatar Fabrice Di Meglio
Browse files

Fix bug #8217354 Suspicious behavior in RTL support for a RelativeLayout

- make rules resolution follow the same pattern as padding and other
RTL properties

Change-Id: Ia0f460f188063f950bc311b51765fdec2f96f542
parent c7ede61f
Loading
Loading
Loading
Loading
+128 −18
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.RemoteViews.RemoteView;

import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
import static android.util.Log.d;

/**
@@ -1223,6 +1224,7 @@ public class RelativeLayout extends ViewGroup {
        private int mEnd = DEFAULT_RELATIVE;

        private boolean mRulesChanged = false;
        private boolean mIsRtlCompatibilityMode = false;

        /**
         * When true, uses the parent as the anchor if the anchor doesn't exist or if
@@ -1237,6 +1239,10 @@ public class RelativeLayout extends ViewGroup {
            TypedArray a = c.obtainStyledAttributes(attrs,
                    com.android.internal.R.styleable.RelativeLayout_Layout);

            final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
            mIsRtlCompatibilityMode = (targetSdkVersion < JELLY_BEAN_MR1 ||
                    !c.getApplicationInfo().hasRtlSupport());

            final int[] rules = mRules;
            //noinspection MismatchedReadAndWriteOfArray
            final int[] initialRules = mInitialRules;
@@ -1405,28 +1411,132 @@ public class RelativeLayout extends ViewGroup {
                    mInitialRules[ALIGN_PARENT_START] != 0 || mInitialRules[ALIGN_PARENT_END] != 0);
        }

        // The way we are resolving rules depends on the layout direction and if we are pre JB MR1
        // or not.
        //
        // If we are pre JB MR1 (said as "RTL compatibility mode"), "left"/"right" rules are having
        // predominance over any "start/end" rules that could have been defined. A special case:
        // if no "left"/"right" rule has been defined and "start"/"end" rules are defined then we
        // resolve those "start"/"end" rules to "left"/"right" respectively.
        //
        // If we are JB MR1+, then "start"/"end" rules are having predominance over "left"/"right"
        // rules. If no "start"/"end" rule is defined then we use "left"/"right" rules.
        //
        // In all cases, the result of the resolution should clear the "start"/"end" rules to leave
        // only the "left"/"right" rules at the end.
        private void resolveRules(int layoutDirection) {
            final boolean isLayoutRtl = (layoutDirection == View.LAYOUT_DIRECTION_RTL);

            // Reset to initial state
            System.arraycopy(mInitialRules, LEFT_OF, mRules, LEFT_OF, VERB_COUNT);
            // Apply rules depending on direction

            // Apply rules depending on direction and if we are in RTL compatibility mode
            if (mIsRtlCompatibilityMode) {
                if (mRules[ALIGN_START] != 0) {
                    if (mRules[ALIGN_LEFT] == 0) {
                        // "left" rule is not defined but "start" rule is: use the "start" rule as
                        // the "left" rule
                        mRules[ALIGN_LEFT] = mRules[ALIGN_START];
                    }
                    mRules[ALIGN_START] = 0;
                }

                if (mRules[ALIGN_END] != 0) {
                    if (mRules[ALIGN_RIGHT] == 0) {
                        // "right" rule is not defined but "end" rule is: use the "end" rule as the
                        // "right" rule
                        mRules[ALIGN_RIGHT] = mRules[ALIGN_END];
                    }
                    mRules[ALIGN_END] = 0;
                }

                if (mRules[START_OF] != 0) {
                    if (mRules[LEFT_OF] == 0) {
                        // "left" rule is not defined but "start" rule is: use the "start" rule as
                        // the "left" rule
                        mRules[LEFT_OF] = mRules[START_OF];
                    }
                    mRules[START_OF] = 0;
                }

                if (mRules[END_OF] != 0) {
                    if (mRules[RIGHT_OF] == 0) {
                        // "right" rule is not defined but "end" rule is: use the "end" rule as the
                        // "right" rule
                        mRules[RIGHT_OF] = mRules[END_OF];
                    }
                    mRules[END_OF] = 0;
                }

                if (mRules[ALIGN_PARENT_START] != 0) {
                    if (mRules[ALIGN_PARENT_LEFT] == 0) {
                        // "left" rule is not defined but "start" rule is: use the "start" rule as
                        // the "left" rule
                        mRules[ALIGN_PARENT_LEFT] = mRules[ALIGN_PARENT_START];
                    }
                    mRules[ALIGN_PARENT_START] = 0;
                }

                if (mRules[ALIGN_PARENT_RIGHT] == 0) {
                    if (mRules[ALIGN_PARENT_RIGHT] == 0) {
                        // "right" rule is not defined but "end" rule is: use the "end" rule as the
                        // "right" rule
                        mRules[ALIGN_PARENT_RIGHT] = mRules[ALIGN_PARENT_END];
                    }
                    mRules[ALIGN_PARENT_END] = 0;
                }
            } else {
                // JB MR1+ case
                if ((mRules[ALIGN_START] != 0 || mRules[ALIGN_END] != 0) &&
                        (mRules[ALIGN_LEFT] != 0 || mRules[ALIGN_RIGHT] != 0)) {
                    // "start"/"end" rules take precedence over "left"/"right" rules
                    mRules[ALIGN_LEFT] = 0;
                    mRules[ALIGN_RIGHT] = 0;
                }
                if (mRules[ALIGN_START] != 0) {
                    // "start" rule resolved to "left" or "right" depending on the direction
                    mRules[isLayoutRtl ? ALIGN_RIGHT : ALIGN_LEFT] = mRules[ALIGN_START];
                    mRules[ALIGN_START] = 0;
                }
                if (mRules[ALIGN_END] != 0) {
                    // "end" rule resolved to "left" or "right" depending on the direction
                    mRules[isLayoutRtl ? ALIGN_LEFT : ALIGN_RIGHT] = mRules[ALIGN_END];
                    mRules[ALIGN_END] = 0;
                }

                if ((mRules[START_OF] != 0 || mRules[END_OF] != 0) &&
                        (mRules[LEFT_OF] != 0 || mRules[RIGHT_OF] != 0)) {
                    // "start"/"end" rules take precedence over "left"/"right" rules
                    mRules[LEFT_OF] = 0;
                    mRules[RIGHT_OF] = 0;
                }
                if (mRules[START_OF] != 0) {
                    // "start" rule resolved to "left" or "right" depending on the direction
                    mRules[isLayoutRtl ? RIGHT_OF : LEFT_OF] = mRules[START_OF];
                    mRules[START_OF] = 0;
                }
                if (mRules[END_OF] != 0) {
                    // "end" rule resolved to "left" or "right" depending on the direction
                    mRules[isLayoutRtl ? LEFT_OF : RIGHT_OF] = mRules[END_OF];
                    mRules[END_OF] = 0;
                }

                if ((mRules[ALIGN_PARENT_START] != 0 || mRules[ALIGN_PARENT_END] != 0) &&
                        (mRules[ALIGN_PARENT_LEFT] != 0 || mRules[ALIGN_PARENT_RIGHT] != 0)) {
                    // "start"/"end" rules take precedence over "left"/"right" rules
                    mRules[ALIGN_PARENT_LEFT] = 0;
                    mRules[ALIGN_PARENT_RIGHT] = 0;
                }
                if (mRules[ALIGN_PARENT_START] != 0) {
                    // "start" rule resolved to "left" or "right" depending on the direction
                    mRules[isLayoutRtl ? ALIGN_PARENT_RIGHT : ALIGN_PARENT_LEFT] = mRules[ALIGN_PARENT_START];
                    mRules[ALIGN_PARENT_START] = 0;
                }
                if (mRules[ALIGN_PARENT_END] != 0) {
                    // "end" rule resolved to "left" or "right" depending on the direction
                    mRules[isLayoutRtl ? ALIGN_PARENT_LEFT : ALIGN_PARENT_RIGHT] = mRules[ALIGN_PARENT_END];
                    mRules[ALIGN_PARENT_END] = 0;
                }
            }
            mRulesChanged = false;
        }