From bb0cbae441f04c052dd1a73448ae58fbffaca65d Mon Sep 17 00:00:00 2001 From: Fabrice Di Meglio Date: Tue, 13 Nov 2012 20:51:24 -0800 Subject: 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 --- core/java/android/widget/Editor.java | 56 ++++-- core/java/android/widget/TextView.java | 195 ++++++++++++++------- .../drawable-ldrtl-hdpi/popup_inline_error.9.png | Bin 0 -> 2388 bytes .../popup_inline_error_above.9.png | Bin 0 -> 2409 bytes .../popup_inline_error_above_holo_dark.9.png | Bin 0 -> 940 bytes .../popup_inline_error_above_holo_light.9.png | Bin 0 -> 932 bytes .../popup_inline_error_holo_dark.9.png | Bin 0 -> 915 bytes .../popup_inline_error_holo_light.9.png | Bin 0 -> 919 bytes .../drawable-ldrtl-ldpi/popup_inline_error.9.png | Bin 0 -> 1115 bytes .../popup_inline_error_above.9.png | Bin 0 -> 1150 bytes .../drawable-ldrtl-mdpi/popup_inline_error.9.png | Bin 0 -> 1536 bytes .../popup_inline_error_above.9.png | Bin 0 -> 1546 bytes .../popup_inline_error_above_holo_dark.9.png | Bin 0 -> 646 bytes .../popup_inline_error_above_holo_light.9.png | Bin 0 -> 636 bytes .../popup_inline_error_holo_dark.9.png | Bin 0 -> 626 bytes .../popup_inline_error_holo_light.9.png | Bin 0 -> 622 bytes .../drawable-ldrtl-xhdpi/popup_inline_error.9.png | Bin 0 -> 4334 bytes .../popup_inline_error_above.9.png | Bin 0 -> 4335 bytes .../popup_inline_error_above_holo_dark.9.png | Bin 0 -> 1264 bytes .../popup_inline_error_above_holo_light.9.png | Bin 0 -> 1255 bytes .../popup_inline_error_holo_dark.9.png | Bin 0 -> 1238 bytes .../popup_inline_error_holo_light.9.png | Bin 0 -> 1229 bytes 22 files changed, 178 insertions(+), 73 deletions(-) create mode 100644 core/res/res/drawable-ldrtl-hdpi/popup_inline_error.9.png create mode 100644 core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above.9.png create mode 100644 core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_dark.9.png create mode 100644 core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_light.9.png create mode 100644 core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_dark.9.png create mode 100644 core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_light.9.png create mode 100644 core/res/res/drawable-ldrtl-ldpi/popup_inline_error.9.png create mode 100644 core/res/res/drawable-ldrtl-ldpi/popup_inline_error_above.9.png create mode 100644 core/res/res/drawable-ldrtl-mdpi/popup_inline_error.9.png create mode 100644 core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above.9.png create mode 100644 core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_dark.9.png create mode 100644 core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_light.9.png create mode 100644 core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_dark.9.png create mode 100644 core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_light.9.png create mode 100644 core/res/res/drawable-ldrtl-xhdpi/popup_inline_error.9.png create mode 100644 core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above.9.png create mode 100644 core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_dark.9.png create mode 100644 core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_light.9.png create mode 100644 core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_dark.9.png create mode 100644 core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_light.9.png diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 521e68606c67..85972c3ff6fa 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -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); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 5d904004cf02..97c78ee630a4 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -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; } diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error.9.png new file mode 100644 index 000000000000..8b43f4ee333c Binary files /dev/null and b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error.9.png differ diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above.9.png new file mode 100644 index 000000000000..20e9002008bb Binary files /dev/null and b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above.9.png differ diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_dark.9.png new file mode 100644 index 000000000000..b5f397c46411 Binary files /dev/null and b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_dark.9.png differ diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_light.9.png new file mode 100644 index 000000000000..a04d6954d785 Binary files /dev/null and b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_light.9.png differ diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_dark.9.png new file mode 100644 index 000000000000..8567b1f3a837 Binary files /dev/null and b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_dark.9.png differ diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_light.9.png new file mode 100644 index 000000000000..7d1754ce0ef7 Binary files /dev/null and b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_light.9.png differ diff --git a/core/res/res/drawable-ldrtl-ldpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error.9.png new file mode 100644 index 000000000000..d2efb6241bc7 Binary files /dev/null and b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error.9.png differ diff --git a/core/res/res/drawable-ldrtl-ldpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error_above.9.png new file mode 100644 index 000000000000..04d200dcb4c9 Binary files /dev/null and b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error_above.9.png differ diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error.9.png new file mode 100644 index 000000000000..27e8d4fe420d Binary files /dev/null and b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error.9.png differ diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above.9.png new file mode 100644 index 000000000000..4ae2b91d1fbf Binary files /dev/null and b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above.9.png differ diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_dark.9.png new file mode 100644 index 000000000000..8cc3b693f082 Binary files /dev/null and b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_dark.9.png differ diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_light.9.png new file mode 100644 index 000000000000..7a84200d72dd Binary files /dev/null and b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_light.9.png differ diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_dark.9.png new file mode 100644 index 000000000000..8fc2e2ed9759 Binary files /dev/null and b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_dark.9.png differ diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_light.9.png new file mode 100644 index 000000000000..687a691ad698 Binary files /dev/null and b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_light.9.png differ diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error.9.png new file mode 100644 index 000000000000..db91a5660466 Binary files /dev/null and b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error.9.png differ diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above.9.png new file mode 100644 index 000000000000..90820b5fa9a0 Binary files /dev/null and b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above.9.png differ diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_dark.9.png new file mode 100644 index 000000000000..598997518833 Binary files /dev/null and b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_dark.9.png differ diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_light.9.png new file mode 100644 index 000000000000..3b3f87d3af10 Binary files /dev/null and b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_light.9.png differ diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_dark.9.png new file mode 100644 index 000000000000..75baba28be9e Binary files /dev/null and b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_dark.9.png differ diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_light.9.png new file mode 100644 index 000000000000..6c0203da995e Binary files /dev/null and b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_light.9.png differ -- cgit v1.2.3-59-g8ed1b