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

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

Fix bug #9302365 HorizontalScrollView is not RTL aware

- make FrameLayout capable of forcing a Gravity.LEFT (when there will be
only one child with Gravity.RIGHT and wider than its parent like for
HorizontalScrollView)
- fix onLayout() so that it is forcing Gravity.LEFT if needed and
setting correctly the initial mScrollX
- also add restore/save from an instance state (by saving if the layout
is RTL and the scroll position)

Change-Id: Ida7ff4654c6a54a1696c2575af46f044dd1aabc8
parent 97f41383
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
@@ -267,12 +267,12 @@ public class FrameLayout extends ViewGroup {
        return mForeground;
    }

    private int getPaddingLeftWithForeground() {
    int getPaddingLeftWithForeground() {
        return mForegroundInPadding ? Math.max(mPaddingLeft, mForegroundPaddingLeft) :
            mPaddingLeft + mForegroundPaddingLeft;
    }

    private int getPaddingRightWithForeground() {
    int getPaddingRightWithForeground() {
        return mForegroundInPadding ? Math.max(mPaddingRight, mForegroundPaddingRight) :
            mPaddingRight + mForegroundPaddingRight;
    }
@@ -385,6 +385,11 @@ public class FrameLayout extends ViewGroup {
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        layoutChildren(left, top, right, bottom, false /* no force left gravity */);
    }

    void layoutChildren(int left, int top, int right, int bottom,
                                  boolean forceLeftGravity) {
        final int count = getChildCount();

        final int parentLeft = getPaddingLeftWithForeground();
@@ -416,16 +421,16 @@ public class FrameLayout extends ViewGroup {
                final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;

                switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
                    case Gravity.LEFT:
                        childLeft = parentLeft + lp.leftMargin;
                        break;
                    case Gravity.CENTER_HORIZONTAL:
                        childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
                        lp.leftMargin - lp.rightMargin;
                        break;
                    case Gravity.RIGHT:
                        if (!forceLeftGravity) {
                            childLeft = parentRight - width - lp.rightMargin;
                            break;
                        }
                    case Gravity.LEFT:
                    default:
                        childLeft = parentLeft + lp.leftMargin;
                }
+92 −1
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.FocusFinder;
@@ -133,6 +135,8 @@ public class HorizontalScrollView extends FrameLayout {
     */
    private static final int INVALID_POINTER = -1;

    private SavedState mSavedState;

    public HorizontalScrollView(Context context) {
        this(context, null);
    }
@@ -1452,7 +1456,14 @@ public class HorizontalScrollView extends FrameLayout {

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        // There is only one child
        final View child = getChildAt(0);
        final int childWidth = child.getMeasuredWidth();
        final LayoutParams childParams = (LayoutParams) child.getLayoutParams();
        final int available = r - l - getPaddingLeftWithForeground() -
                getPaddingRightWithForeground() - childParams.leftMargin - childParams.rightMargin;
        final boolean forceLeftGravity = (childWidth > available);
        layoutChildren(l, t, r, b, forceLeftGravity);
        mIsLayoutDirty = false;
        // Give a child focus if it needs it
        if (mChildToScrollTo != null && isViewDescendantOf(mChildToScrollTo, this)) {
@@ -1460,6 +1471,28 @@ public class HorizontalScrollView extends FrameLayout {
        }
        mChildToScrollTo = null;

        if (!hasLayout()) {
            final int scrollRange = Math.max(0,
                    childWidth - (r - l - mPaddingLeft - mPaddingRight));
            if (mSavedState != null) {
                if (isLayoutRtl() == mSavedState.isLayoutRtl) {
                    mScrollX = mSavedState.scrollPosition;
                } else {
                    mScrollX = scrollRange - mSavedState.scrollPosition;
                }
            } else {
                if (isLayoutRtl()) {
                    mScrollX = scrollRange - mScrollX;
                } // mScrollX default value is "0" for LTR
            }
            // Don't forget to clamp
            if (mScrollX > scrollRange) {
                mScrollX = scrollRange;
            } else if (mScrollX < 0) {
                mScrollX = 0;
            }
        }

        // Calling this with the present values causes it to re-claim them
        scrollTo(mScrollX, mScrollY);
    }
@@ -1604,4 +1637,62 @@ public class HorizontalScrollView extends FrameLayout {
        }
        return n;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());
        mSavedState = ss;
        requestLayout();
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);
        ss.scrollPosition = mScrollX;
        ss.isLayoutRtl = isLayoutRtl();
        return ss;
    }

    static class SavedState extends BaseSavedState {
        public int scrollPosition;
        public boolean isLayoutRtl;

        SavedState(Parcelable superState) {
            super(superState);
        }

        public SavedState(Parcel source) {
            super(source);
            scrollPosition = source.readInt();
            isLayoutRtl = (source.readInt() == 0) ? true : false;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            super.writeToParcel(dest, flags);
            dest.writeInt(scrollPosition);
            dest.writeInt(isLayoutRtl ? 1 : 0);
        }

        @Override
        public String toString() {
            return "HorizontalScrollView.SavedState{"
                    + Integer.toHexString(System.identityHashCode(this))
                    + " scrollPosition=" + scrollPosition
                    + " isLayoutRtl=" + isLayoutRtl + "}";
        }

        public static final Parcelable.Creator<SavedState> CREATOR
                = new Parcelable.Creator<SavedState>() {
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }
}