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

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

Fix for bug #7417949 TextView / EditText error Drawable is not put on the left in RTL mode

- keep the Error Drawable infos into the Drawables cache
- reset left/right Drawable state before resolving where to put the Error Drawable
- get the mirrored Drawable for the Error popup background
- set the Error popup position depending on the layout direction (so that the "triangle"
of the background is pointing to the middle of the Error icon)

One restriction: we load the Error popup background Drawable corresponding to the layout
direction of the System Locale. So if you set the Layout direction on a TextView (or
an EditText) to RTL and set an error to it when you are in a RTL System Locale, then you
see that the background "triangle" is not pointing to the Error icon. This is working as
intended as the AssetManager load the Drawable resource depending on the configuration
which is in that case the RTL one thus loading the RTL version of the background (and not
the LTR one).

Thus there can be a discrepancy between the "layout direction" of the TextView
and the one from the Error popup background. This would happen only thru using the SDK and
not in a normal case when running an App.

Change-Id: I91bbfbe46ac20efe0e585c5d4c766db23b5c709d
parent 5acc379c
Loading
Loading
Loading
Loading
+42 −14
Original line number Diff line number Diff line
@@ -309,13 +309,15 @@ public class Editor {
    }

    private void setErrorIcon(Drawable icon) {
        final Drawables dr = mTextView.mDrawables;
        if (dr != null) {
            mTextView.setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon,
                    dr.mDrawableBottom);
        } else {
            mTextView.setCompoundDrawables(null, null, icon, null);
        Drawables dr = mTextView.mDrawables;
        if (dr == null) {
            mTextView.mDrawables = dr = new Drawables();
        }
        dr.setErrorDrawable(icon, mTextView);

        mTextView.resetResolvedDrawables();
        mTextView.invalidate();
        mTextView.requestLayout();
    }

    private void hideError() {
@@ -329,7 +331,7 @@ public class Editor {
    }

    /**
     * Returns the Y offset to make the pointy top of the error point
     * Returns the X offset to make the pointy top of the error point
     * at the middle of the error icon.
     */
    private int getErrorX() {
@@ -340,8 +342,23 @@ public class Editor {
        final float scale = mTextView.getResources().getDisplayMetrics().density;

        final Drawables dr = mTextView.mDrawables;
        return mTextView.getWidth() - mErrorPopup.getWidth() - mTextView.getPaddingRight() -
                (dr != null ? dr.mDrawableSizeRight : 0) / 2 + (int) (25 * scale + 0.5f);

        final int layoutDirection = mTextView.getLayoutDirection();
        int errorX;
        int offset;
        switch (layoutDirection) {
            default:
            case View.LAYOUT_DIRECTION_LTR:
                offset = - (dr != null ? dr.mDrawableSizeRight : 0) / 2 + (int) (25 * scale + 0.5f);
                errorX = mTextView.getWidth() - mErrorPopup.getWidth() -
                        mTextView.getPaddingRight() + offset;
                break;
            case View.LAYOUT_DIRECTION_RTL:
                offset = (dr != null ? dr.mDrawableSizeLeft : 0) / 2 - (int) (25 * scale + 0.5f);
                errorX = mTextView.getPaddingLeft() + offset;
                break;
        }
        return errorX;
    }

    /**
@@ -358,16 +375,27 @@ public class Editor {
                mTextView.getCompoundPaddingBottom() - compoundPaddingTop;

        final Drawables dr = mTextView.mDrawables;
        int icontop = compoundPaddingTop +
                (vspace - (dr != null ? dr.mDrawableHeightRight : 0)) / 2;

        final int layoutDirection = mTextView.getLayoutDirection();
        int height;
        switch (layoutDirection) {
            default:
            case View.LAYOUT_DIRECTION_LTR:
                height = (dr != null ? dr.mDrawableHeightRight : 0);
                break;
            case View.LAYOUT_DIRECTION_RTL:
                height = (dr != null ? dr.mDrawableHeightLeft : 0);
                break;
        }

        int icontop = compoundPaddingTop + (vspace - height) / 2;

        /*
         * The "2" is the distance between the point and the top edge
         * of the background.
         */
        final float scale = mTextView.getResources().getDisplayMetrics().density;
        return icontop + (dr != null ? dr.mDrawableHeightRight : 0) - mTextView.getHeight() -
                (int) (2 * scale + 0.5f);
        return icontop + height - mTextView.getHeight() - (int) (2 * scale + 0.5f);
    }

    void createInputContentTypeIfNeeded() {
@@ -3726,7 +3754,7 @@ public class Editor {
            super(v, width, height);
            mView = v;
            // Make sure the TextView has a background set as it will be used the first time it is
            // shown and positionned. Initialized with below background, which should have
            // shown and positioned. Initialized with below background, which should have
            // dimensions identical to the above version for this to work (and is more likely).
            mPopupInlineErrorBackgroundId = getResourceId(mPopupInlineErrorBackgroundId,
                    com.android.internal.R.styleable.Theme_errorMessageBackground);
+136 −59
Original line number Diff line number Diff line
@@ -284,15 +284,144 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    private TextUtils.TruncateAt mEllipsize;

    static class Drawables {
        final static int DRAWABLE_NONE = -1;
        final static int DRAWABLE_RIGHT = 0;
        final static int DRAWABLE_LEFT = 1;

        final Rect mCompoundRect = new Rect();

        Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight,
                mDrawableStart, mDrawableEnd;
                mDrawableStart, mDrawableEnd, mDrawableError, mDrawableTemp;

        int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight,
                mDrawableSizeStart, mDrawableSizeEnd;
                mDrawableSizeStart, mDrawableSizeEnd, mDrawableSizeError, mDrawableSizeTemp;

        int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight,
                mDrawableHeightStart, mDrawableHeightEnd;
                mDrawableHeightStart, mDrawableHeightEnd, mDrawableHeightError, mDrawableHeightTemp;

        int mDrawablePadding;

        int mDrawableSaved = DRAWABLE_NONE;

        public void resolveWithLayoutDirection(int layoutDirection) {
            switch(layoutDirection) {
                case LAYOUT_DIRECTION_RTL:
                    if (mDrawableStart != null) {
                        mDrawableRight = mDrawableStart;

                        mDrawableSizeRight = mDrawableSizeStart;
                        mDrawableHeightRight = mDrawableHeightStart;
                    }
                    if (mDrawableEnd != null) {
                        mDrawableLeft = mDrawableEnd;

                        mDrawableSizeLeft = mDrawableSizeEnd;
                        mDrawableHeightLeft = mDrawableHeightEnd;
                    }
                    break;

                case LAYOUT_DIRECTION_LTR:
                default:
                    if (mDrawableStart != null) {
                        mDrawableLeft = mDrawableStart;

                        mDrawableSizeLeft = mDrawableSizeStart;
                        mDrawableHeightLeft = mDrawableHeightStart;
                    }
                    if (mDrawableEnd != null) {
                        mDrawableRight = mDrawableEnd;

                        mDrawableSizeRight = mDrawableSizeEnd;
                        mDrawableHeightRight = mDrawableHeightEnd;
                    }
                    break;
            }
            applyErrorDrawableIfNeeded(layoutDirection);
            updateDrawablesLayoutDirection(layoutDirection);
        }

        private void updateDrawablesLayoutDirection(int layoutDirection) {
            if (mDrawableLeft != null) {
                mDrawableLeft.setLayoutDirection(layoutDirection);
            }
            if (mDrawableRight != null) {
                mDrawableRight.setLayoutDirection(layoutDirection);
            }
            if (mDrawableTop != null) {
                mDrawableTop.setLayoutDirection(layoutDirection);
            }
            if (mDrawableBottom != null) {
                mDrawableBottom.setLayoutDirection(layoutDirection);
            }
        }

        public void setErrorDrawable(Drawable dr, TextView tv) {
            if (mDrawableError != dr && mDrawableError != null) {
                mDrawableError.setCallback(null);
            }
            mDrawableError = dr;

            final Rect compoundRect = mCompoundRect;
            int[] state = tv.getDrawableState();

            if (mDrawableError != null) {
                mDrawableError.setState(state);
                mDrawableError.copyBounds(compoundRect);
                mDrawableError.setCallback(tv);
                mDrawableSizeError = compoundRect.width();
                mDrawableHeightError = compoundRect.height();
            } else {
                mDrawableSizeError = mDrawableHeightError = 0;
            }
        }

        private void applyErrorDrawableIfNeeded(int layoutDirection) {
            // first restore the initial state if needed
            switch (mDrawableSaved) {
                case DRAWABLE_LEFT:
                    mDrawableLeft = mDrawableTemp;
                    mDrawableSizeLeft = mDrawableSizeTemp;
                    mDrawableHeightLeft = mDrawableHeightTemp;
                    break;
                case DRAWABLE_RIGHT:
                    mDrawableRight = mDrawableTemp;
                    mDrawableSizeRight = mDrawableSizeTemp;
                    mDrawableHeightRight = mDrawableHeightTemp;
                    break;
                case DRAWABLE_NONE:
                default:
            }
            // then, if needed, assign the Error drawable to the correct location
            if (mDrawableError != null) {
                switch(layoutDirection) {
                    case LAYOUT_DIRECTION_RTL:
                        mDrawableSaved = DRAWABLE_LEFT;

                        mDrawableTemp = mDrawableLeft;
                        mDrawableSizeTemp = mDrawableSizeLeft;
                        mDrawableHeightTemp = mDrawableHeightLeft;

                        mDrawableLeft = mDrawableError;
                        mDrawableSizeLeft = mDrawableSizeError;
                        mDrawableHeightLeft = mDrawableHeightError;
                        break;
                    case LAYOUT_DIRECTION_LTR:
                    default:
                        mDrawableSaved = DRAWABLE_RIGHT;

                        mDrawableTemp = mDrawableRight;
                        mDrawableSizeTemp = mDrawableSizeRight;
                        mDrawableHeightTemp = mDrawableHeightRight;

                        mDrawableRight = mDrawableError;
                        mDrawableSizeRight = mDrawableSizeError;
                        mDrawableHeightRight = mDrawableHeightError;
                        break;
                }
            }
        }
    }

    Drawables mDrawables;

    private CharWrapper mCharWrapper;
@@ -8264,63 +8393,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            return;
        }
        mLastLayoutDirection = layoutDirection;
        // No drawable to resolve
        if (mDrawables == null) {
            return;
        }
        // No relative drawable to resolve
        if (mDrawables.mDrawableStart == null && mDrawables.mDrawableEnd == null) {
            return;
        }

        Drawables dr = mDrawables;
        switch(layoutDirection) {
            case LAYOUT_DIRECTION_RTL:
                if (dr.mDrawableStart != null) {
                    dr.mDrawableRight = dr.mDrawableStart;

                    dr.mDrawableSizeRight = dr.mDrawableSizeStart;
                    dr.mDrawableHeightRight = dr.mDrawableHeightStart;
                }
                if (dr.mDrawableEnd != null) {
                    dr.mDrawableLeft = dr.mDrawableEnd;

                    dr.mDrawableSizeLeft = dr.mDrawableSizeEnd;
                    dr.mDrawableHeightLeft = dr.mDrawableHeightEnd;
                }
                break;

            case LAYOUT_DIRECTION_LTR:
            default:
                if (dr.mDrawableStart != null) {
                    dr.mDrawableLeft = dr.mDrawableStart;

                    dr.mDrawableSizeLeft = dr.mDrawableSizeStart;
                    dr.mDrawableHeightLeft = dr.mDrawableHeightStart;
                }
                if (dr.mDrawableEnd != null) {
                    dr.mDrawableRight = dr.mDrawableEnd;

                    dr.mDrawableSizeRight = dr.mDrawableSizeEnd;
                    dr.mDrawableHeightRight = dr.mDrawableHeightEnd;
                }
                break;
        }
        updateDrawablesLayoutDirection(dr, layoutDirection);
    }

    private void updateDrawablesLayoutDirection(Drawables dr, int layoutDirection) {
        if (dr.mDrawableLeft != null) {
            dr.mDrawableLeft.setLayoutDirection(layoutDirection);
        }
        if (dr.mDrawableRight != null) {
            dr.mDrawableRight.setLayoutDirection(layoutDirection);
        }
        if (dr.mDrawableTop != null) {
            dr.mDrawableTop.setLayoutDirection(layoutDirection);
        }
        if (dr.mDrawableBottom != null) {
            dr.mDrawableBottom.setLayoutDirection(layoutDirection);
        // Resolve drawables
        if (mDrawables != null) {
            mDrawables.resolveWithLayoutDirection(layoutDirection);
        }
    }

@@ -8328,6 +8404,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     * @hide
     */
    protected void resetResolvedDrawables() {
        super.resetResolvedDrawables();
        mLastLayoutDirection = -1;
    }

+2.33 KiB
Loading image diff...
+2.35 KiB
Loading image diff...
+940 B
Loading image diff...
Loading