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

Commit 0072f649 authored by Fabrice Di Meglio's avatar Fabrice Di Meglio
Browse files

Fix bug #8480245 ViewGroup layout margins can be wrong in RTL mode

- fix resolution of MarginLayoutParams
- update related RelativeLayout code

Change-Id: I261f127a8897f60d316fed2a73e6e76020e542cc
parent 3bafc1a7
Loading
Loading
Loading
Loading
+78 −37
Original line number Diff line number Diff line
@@ -51,6 +51,8 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;

import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;

/**
 * <p>
 * A <code>ViewGroup</code> is a special view that can contain other views
@@ -5861,7 +5863,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
         * to this field.
         */
        @ViewDebug.ExportedProperty(category = "layout")
        private int startMargin = DEFAULT_RELATIVE;
        private int startMargin = DEFAULT_MARGIN_RELATIVE;

        /**
         * The end margin in pixels of the child.
@@ -5869,21 +5871,21 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
         * to this field.
         */
        @ViewDebug.ExportedProperty(category = "layout")
        private int endMargin = DEFAULT_RELATIVE;
        private int endMargin = DEFAULT_MARGIN_RELATIVE;

        /**
         * The default start and end margin.
         * @hide
         */
        public static final int DEFAULT_RELATIVE = Integer.MIN_VALUE;
        public static final int DEFAULT_MARGIN_RELATIVE = Integer.MIN_VALUE;

        private int initialLeftMargin;
        private int initialRightMargin;
        // Layout direction is LTR by default
        private int mLayoutDirection = LAYOUT_DIRECTION_LTR;

        private static int LAYOUT_DIRECTION_UNDEFINED = -1;
        private static int DEFAULT_MARGIN_RESOLVED = 0;

        // Layout direction undefined by default
        private int layoutDirection = LAYOUT_DIRECTION_UNDEFINED;
        private boolean mNeedResolution = false;
        private boolean mIsRtlCompatibilityMode = true;

        /**
         * Creates a new set of layout parameters. The values are extracted from
@@ -5910,21 +5912,30 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                bottomMargin = margin;
            } else {
                leftMargin = a.getDimensionPixelSize(
                        R.styleable.ViewGroup_MarginLayout_layout_marginLeft, 0);
                        R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
                        DEFAULT_MARGIN_RESOLVED);
                topMargin = a.getDimensionPixelSize(
                        R.styleable.ViewGroup_MarginLayout_layout_marginTop, 0);
                        R.styleable.ViewGroup_MarginLayout_layout_marginTop,
                        DEFAULT_MARGIN_RESOLVED);
                rightMargin = a.getDimensionPixelSize(
                        R.styleable.ViewGroup_MarginLayout_layout_marginRight, 0);
                        R.styleable.ViewGroup_MarginLayout_layout_marginRight,
                        DEFAULT_MARGIN_RESOLVED);
                bottomMargin = a.getDimensionPixelSize(
                        R.styleable.ViewGroup_MarginLayout_layout_marginBottom, 0);
                        R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
                        DEFAULT_MARGIN_RESOLVED);
                startMargin = a.getDimensionPixelSize(
                        R.styleable.ViewGroup_MarginLayout_layout_marginStart, DEFAULT_RELATIVE);
                        R.styleable.ViewGroup_MarginLayout_layout_marginStart,
                        DEFAULT_MARGIN_RELATIVE);
                endMargin = a.getDimensionPixelSize(
                        R.styleable.ViewGroup_MarginLayout_layout_marginEnd, DEFAULT_RELATIVE);
                        R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
                        DEFAULT_MARGIN_RELATIVE);

                mNeedResolution = isMarginRelative();
            }

            initialLeftMargin = leftMargin;
            initialRightMargin = rightMargin;
            final boolean hasRtlSupport = c.getApplicationInfo().hasRtlSupport();
            final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
            mIsRtlCompatibilityMode = targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport;

            a.recycle();
        }
@@ -5934,6 +5945,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
         */
        public MarginLayoutParams(int width, int height) {
            super(width, height);

            mNeedResolution = false;
            mIsRtlCompatibilityMode = false;
        }

        /**
@@ -5952,10 +5966,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            this.startMargin = source.startMargin;
            this.endMargin = source.endMargin;

            this.initialLeftMargin = source.leftMargin;
            this.initialRightMargin = source.rightMargin;
            this.mNeedResolution = source.mNeedResolution;
            this.mIsRtlCompatibilityMode = source.mIsRtlCompatibilityMode;

            setLayoutDirection(source.layoutDirection);
            setLayoutDirection(source.mLayoutDirection);
        }

        /**
@@ -5963,6 +5977,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
         */
        public MarginLayoutParams(LayoutParams source) {
            super(source);

            mNeedResolution = false;
            mIsRtlCompatibilityMode = false;
        }

        /**
@@ -5985,8 +6002,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            topMargin = top;
            rightMargin = right;
            bottomMargin = bottom;
            initialLeftMargin = left;
            initialRightMargin = right;
            mNeedResolution = isMarginRelative();
        }

        /**
@@ -6012,8 +6028,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            topMargin = top;
            endMargin = end;
            bottomMargin = bottom;
            initialLeftMargin = 0;
            initialRightMargin = 0;
            mNeedResolution = true;
        }

        /**
@@ -6025,6 +6040,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
         */
        public void setMarginStart(int start) {
            startMargin = start;
            mNeedResolution = true;
        }

        /**
@@ -6035,8 +6051,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
         * @return the start margin in pixels.
         */
        public int getMarginStart() {
            if (startMargin != DEFAULT_RELATIVE) return startMargin;
            switch(layoutDirection) {
            if (startMargin != DEFAULT_MARGIN_RELATIVE) return startMargin;
            if (mNeedResolution) {
                doResolveMargins();
            }
            switch(mLayoutDirection) {
                case View.LAYOUT_DIRECTION_RTL:
                    return rightMargin;
                case View.LAYOUT_DIRECTION_LTR:
@@ -6054,6 +6073,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
         */
        public void setMarginEnd(int end) {
            endMargin = end;
            mNeedResolution = true;
        }

        /**
@@ -6064,8 +6084,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
         * @return the end margin in pixels.
         */
        public int getMarginEnd() {
            if (endMargin != DEFAULT_RELATIVE) return endMargin;
            switch(layoutDirection) {
            if (endMargin != DEFAULT_MARGIN_RELATIVE) return endMargin;
            if (mNeedResolution) {
                doResolveMargins();
            }
            switch(mLayoutDirection) {
                case View.LAYOUT_DIRECTION_RTL:
                    return leftMargin;
                case View.LAYOUT_DIRECTION_LTR:
@@ -6083,7 +6106,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
         * @return true if either marginStart or marginEnd has been set.
         */
        public boolean isMarginRelative() {
            return (startMargin != DEFAULT_RELATIVE) || (endMargin != DEFAULT_RELATIVE);
            return (startMargin != DEFAULT_MARGIN_RELATIVE || endMargin != DEFAULT_MARGIN_RELATIVE);
        }

        /**
@@ -6095,7 +6118,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        public void setLayoutDirection(int layoutDirection) {
            if (layoutDirection != View.LAYOUT_DIRECTION_LTR &&
                    layoutDirection != View.LAYOUT_DIRECTION_RTL) return;
            this.layoutDirection = layoutDirection;
            if (layoutDirection != this.mLayoutDirection) {
                this.mLayoutDirection = layoutDirection;
                this.mNeedResolution = isMarginRelative();
            }
        }

        /**
@@ -6105,7 +6131,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
         * @return the layout direction.
         */
        public int getLayoutDirection() {
            return layoutDirection;
            return mLayoutDirection;
        }

        /**
@@ -6116,26 +6142,41 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        public void resolveLayoutDirection(int layoutDirection) {
            setLayoutDirection(layoutDirection);

            if (!isMarginRelative()) return;
            // No relative margin or pre JB-MR1 case or no need to resolve, just dont do anything
            // Will use the left and right margins if no relative margin is defined.
            if (!isMarginRelative() || !mNeedResolution || mIsRtlCompatibilityMode) return;

            // Proceed with resolution
            doResolveMargins();
        }

            switch(layoutDirection) {
        private void doResolveMargins() {
            // We have some relative margins (either the start one or the end one or both). So use
            // them and override what has been defined for left and right margins. If either start
            // or end margin is not defined, just set it to default "0".
            switch(mLayoutDirection) {
                case View.LAYOUT_DIRECTION_RTL:
                    leftMargin = (endMargin > DEFAULT_RELATIVE) ? endMargin : initialLeftMargin;
                    rightMargin = (startMargin > DEFAULT_RELATIVE) ? startMargin : initialRightMargin;
                    leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
                            endMargin : DEFAULT_MARGIN_RESOLVED;
                    rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
                            startMargin : DEFAULT_MARGIN_RESOLVED;
                    break;
                case View.LAYOUT_DIRECTION_LTR:
                default:
                    leftMargin = (startMargin > DEFAULT_RELATIVE) ? startMargin : initialLeftMargin;
                    rightMargin = (endMargin > DEFAULT_RELATIVE) ? endMargin : initialRightMargin;
                    leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
                            startMargin : DEFAULT_MARGIN_RESOLVED;
                    rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
                            endMargin : DEFAULT_MARGIN_RESOLVED;
                    break;
            }
            mNeedResolution = false;
        }

        /**
         * @hide
         */
        public boolean isLayoutRtl() {
            return (layoutDirection == View.LAYOUT_DIRECTION_RTL);
            return (mLayoutDirection == View.LAYOUT_DIRECTION_RTL);
        }

        /**
+7 −7
Original line number Diff line number Diff line
@@ -1212,8 +1212,8 @@ public class RelativeLayout extends ViewGroup {

        private int mLeft, mTop, mRight, mBottom;

        private int mStart = DEFAULT_RELATIVE;
        private int mEnd = DEFAULT_RELATIVE;
        private int mStart = DEFAULT_MARGIN_RELATIVE;
        private int mEnd = DEFAULT_MARGIN_RELATIVE;

        private boolean mRulesChanged = false;
        private boolean mIsRtlCompatibilityMode = false;
@@ -1314,7 +1314,7 @@ public class RelativeLayout extends ViewGroup {
                        break;
                }
            }

            mRulesChanged = true;
            System.arraycopy(rules, LEFT_OF, initialRules, LEFT_OF, VERB_COUNT);

            a.recycle();
@@ -1574,11 +1574,11 @@ public class RelativeLayout extends ViewGroup {
        public void resolveLayoutDirection(int layoutDirection) {
            final boolean isLayoutRtl = isLayoutRtl();
            if (isLayoutRtl) {
                if (mStart != DEFAULT_RELATIVE) mRight = mStart;
                if (mEnd != DEFAULT_RELATIVE) mLeft = mEnd;
                if (mStart != DEFAULT_MARGIN_RELATIVE) mRight = mStart;
                if (mEnd != DEFAULT_MARGIN_RELATIVE) mLeft = mEnd;
            } else {
                if (mStart != DEFAULT_RELATIVE) mLeft = mStart;
                if (mEnd != DEFAULT_RELATIVE) mRight = mEnd;
                if (mStart != DEFAULT_MARGIN_RELATIVE) mLeft = mStart;
                if (mEnd != DEFAULT_MARGIN_RELATIVE) mRight = mEnd;
            }

            if (hasRelativeRules() && layoutDirection != getLayoutDirection()) {