Introduce TextView drawableStart and drawableEnd

- update also unit tests

Change-Id: I20b82f5fea2cc48c93fd9e26eb03290ad730c08a
diff --git a/api/current.txt b/api/current.txt
index 2923805..15b1af6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -377,9 +377,11 @@
     field public static final int drawSelectorOnTop = 16843004; // 0x10100fc
     field public static final int drawable = 16843161; // 0x1010199
     field public static final int drawableBottom = 16843118; // 0x101016e
+    field public static final int drawableEnd = 16843687; // 0x10103a7
     field public static final int drawableLeft = 16843119; // 0x101016f
     field public static final int drawablePadding = 16843121; // 0x1010171
     field public static final int drawableRight = 16843120; // 0x1010170
+    field public static final int drawableStart = 16843686; // 0x10103a6
     field public static final int drawableTop = 16843117; // 0x101016d
     field public static final int drawingCacheQuality = 16842984; // 0x10100e8
     field public static final int dropDownAnchor = 16843363; // 0x1010263
@@ -26417,7 +26419,9 @@
     method protected void onTextChanged(java.lang.CharSequence, int, int, int);
     method public boolean onTextContextMenuItem(int);
     method public void removeTextChangedListener(android.text.TextWatcher);
+    method protected void resetResolvedDrawables();
     method protected void resetResolvedLayoutDirection();
+    method protected void resolveDrawables();
     method public void setAllCaps(boolean);
     method public final void setAutoLinkMask(int);
     method public void setCompoundDrawablePadding(int);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index e350ec4..e90bdd0 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -260,9 +260,12 @@
 
     class Drawables {
         final Rect mCompoundRect = new Rect();
-        Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight;
-        int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight;
-        int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight;
+        Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight,
+                mDrawableStart, mDrawableEnd;
+        int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight,
+                mDrawableSizeStart, mDrawableSizeEnd;
+        int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight,
+                mDrawableHeightStart, mDrawableHeightEnd;
         int mDrawablePadding;
     }
     private Drawables mDrawables;
@@ -352,6 +355,8 @@
         INHERIT, GRAVITY, TEXT_START, TEXT_END, CENTER, VIEW_START, VIEW_END;
     }
 
+    private boolean bResolvedDrawables = false;
+
     /*
      * Kick-start the font cache for the zygote process (to pay the cost of
      * initializing freetype for our default font only once).
@@ -494,7 +499,7 @@
         int buffertype = 0;
         boolean selectallonfocus = false;
         Drawable drawableLeft = null, drawableTop = null, drawableRight = null,
-            drawableBottom = null;
+            drawableBottom = null, drawableStart = null, drawableEnd = null;
         int drawablePadding = 0;
         int ellipsize = -1;
         boolean singleLine = false;
@@ -571,6 +576,14 @@
                 drawableBottom = a.getDrawable(attr);
                 break;
 
+            case com.android.internal.R.styleable.TextView_drawableStart:
+                drawableStart = a.getDrawable(attr);
+                break;
+
+            case com.android.internal.R.styleable.TextView_drawableEnd:
+                drawableEnd = a.getDrawable(attr);
+                break;
+
             case com.android.internal.R.styleable.TextView_drawablePadding:
                 drawablePadding = a.getDimensionPixelSize(attr, drawablePadding);
                 break;
@@ -980,6 +993,7 @@
 
         setCompoundDrawablesWithIntrinsicBounds(
             drawableLeft, drawableTop, drawableRight, drawableBottom);
+        setRelativeDrawablesIfNeeded(drawableStart, drawableEnd);
         setCompoundDrawablePadding(drawablePadding);
 
         // Same as setSingleLine(), but make sure the transformation method and the maximum number
@@ -1105,6 +1119,42 @@
         setTypeface(tf, styleIndex);
     }
 
+    private void setRelativeDrawablesIfNeeded(Drawable start, Drawable end) {
+        boolean hasRelativeDrawables = (start != null) || (end != null);
+        if (hasRelativeDrawables) {
+            Drawables dr = mDrawables;
+            if (dr == null) {
+                mDrawables = dr = new Drawables();
+            }
+            final Rect compoundRect = dr.mCompoundRect;
+            int[] state = getDrawableState();
+            if (start != null) {
+                start.setBounds(0, 0, start.getIntrinsicWidth(), start.getIntrinsicHeight());
+                start.setState(state);
+                start.copyBounds(compoundRect);
+                start.setCallback(this);
+
+                dr.mDrawableStart = start;
+                dr.mDrawableSizeStart = compoundRect.width();
+                dr.mDrawableHeightStart = compoundRect.height();
+            } else {
+                dr.mDrawableSizeStart = dr.mDrawableHeightStart = 0;
+            }
+            if (end != null) {
+                end.setBounds(0, 0, end.getIntrinsicWidth(), end.getIntrinsicHeight());
+                end.setState(state);
+                end.copyBounds(compoundRect);
+                end.setCallback(this);
+
+                dr.mDrawableEnd = end;
+                dr.mDrawableSizeEnd = compoundRect.width();
+                dr.mDrawableHeightEnd = compoundRect.height();
+            } else {
+                dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0;
+            }
+        }
+    }
+
     @Override
     public void setEnabled(boolean enabled) {
         if (enabled == isEnabled()) {
@@ -1410,6 +1460,40 @@
     }
 
     /**
+     * Returns the start padding of the view, plus space for the start
+     * Drawable if any.
+     *
+     * @hide
+     */
+    public int getCompoundPaddingStart() {
+        resolveDrawables();
+        switch(getResolvedLayoutDirection()) {
+            default:
+            case LAYOUT_DIRECTION_LTR:
+                return getCompoundPaddingLeft();
+            case LAYOUT_DIRECTION_RTL:
+                return getCompoundPaddingRight();
+        }
+    }
+
+    /**
+     * Returns the end padding of the view, plus space for the end
+     * Drawable if any.
+     *
+     * @hide
+     */
+    public int getCompoundPaddingEnd() {
+        resolveDrawables();
+        switch(getResolvedLayoutDirection()) {
+            default:
+            case LAYOUT_DIRECTION_LTR:
+                return getCompoundPaddingRight();
+            case LAYOUT_DIRECTION_RTL:
+                return getCompoundPaddingLeft();
+        }
+    }
+
+    /**
      * Returns the extended top padding of the view, including both the
      * top Drawable if any and any extra space to keep more than maxLines
      * of text from showing.  It is only valid to call this after measuring.
@@ -1492,6 +1576,26 @@
     }
 
     /**
+     * Returns the total start padding of the view, including the start
+     * Drawable if any.
+     *
+     * @hide
+     */
+    public int getTotalPaddingStart() {
+        return getCompoundPaddingStart();
+    }
+
+    /**
+     * Returns the total end padding of the view, including the end
+     * Drawable if any.
+     *
+     * @hide
+     */
+    public int getTotalPaddingEnd() {
+        return getCompoundPaddingEnd();
+    }
+
+    /**
      * Returns the total top padding of the view, including the top
      * Drawable if any, the extra space to keep more than maxLines
      * from showing, and the vertical offset for gravity, if any.
@@ -1678,6 +1782,185 @@
     }
 
     /**
+     * Sets the Drawables (if any) to appear to the start of, above,
+     * to the end of, and below the text.  Use null if you do not
+     * want a Drawable there.  The Drawables must already have had
+     * {@link Drawable#setBounds} called.
+     *
+     * @attr ref android.R.styleable#TextView_drawableStart
+     * @attr ref android.R.styleable#TextView_drawableTop
+     * @attr ref android.R.styleable#TextView_drawableEnd
+     * @attr ref android.R.styleable#TextView_drawableBottom
+     *
+     * @hide
+     */
+    public void setCompoundDrawablesRelative(Drawable start, Drawable top,
+                                     Drawable end, Drawable bottom) {
+        Drawables dr = mDrawables;
+
+        final boolean drawables = start != null || top != null
+                || end != null || bottom != null;
+
+        if (!drawables) {
+            // Clearing drawables...  can we free the data structure?
+            if (dr != null) {
+                if (dr.mDrawablePadding == 0) {
+                    mDrawables = null;
+                } else {
+                    // We need to retain the last set padding, so just clear
+                    // out all of the fields in the existing structure.
+                    if (dr.mDrawableStart != null) dr.mDrawableStart.setCallback(null);
+                    dr.mDrawableStart = null;
+                    if (dr.mDrawableTop != null) dr.mDrawableTop.setCallback(null);
+                    dr.mDrawableTop = null;
+                    if (dr.mDrawableEnd != null) dr.mDrawableEnd.setCallback(null);
+                    dr.mDrawableEnd = null;
+                    if (dr.mDrawableBottom != null) dr.mDrawableBottom.setCallback(null);
+                    dr.mDrawableBottom = null;
+                    dr.mDrawableSizeStart = dr.mDrawableHeightStart = 0;
+                    dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0;
+                    dr.mDrawableSizeTop = dr.mDrawableWidthTop = 0;
+                    dr.mDrawableSizeBottom = dr.mDrawableWidthBottom = 0;
+                }
+            }
+        } else {
+            if (dr == null) {
+                mDrawables = dr = new Drawables();
+            }
+
+            if (dr.mDrawableStart != start && dr.mDrawableStart != null) {
+                dr.mDrawableStart.setCallback(null);
+            }
+            dr.mDrawableStart = start;
+
+            if (dr.mDrawableTop != top && dr.mDrawableTop != null) {
+                dr.mDrawableTop.setCallback(null);
+            }
+            dr.mDrawableTop = top;
+
+            if (dr.mDrawableEnd != end && dr.mDrawableEnd != null) {
+                dr.mDrawableEnd.setCallback(null);
+            }
+            dr.mDrawableEnd = end;
+
+            if (dr.mDrawableBottom != bottom && dr.mDrawableBottom != null) {
+                dr.mDrawableBottom.setCallback(null);
+            }
+            dr.mDrawableBottom = bottom;
+
+            final Rect compoundRect = dr.mCompoundRect;
+            int[] state;
+
+            state = getDrawableState();
+
+            if (start != null) {
+                start.setState(state);
+                start.copyBounds(compoundRect);
+                start.setCallback(this);
+                dr.mDrawableSizeStart = compoundRect.width();
+                dr.mDrawableHeightStart = compoundRect.height();
+            } else {
+                dr.mDrawableSizeStart = dr.mDrawableHeightStart = 0;
+            }
+
+            if (end != null) {
+                end.setState(state);
+                end.copyBounds(compoundRect);
+                end.setCallback(this);
+                dr.mDrawableSizeEnd = compoundRect.width();
+                dr.mDrawableHeightEnd = compoundRect.height();
+            } else {
+                dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0;
+            }
+
+            if (top != null) {
+                top.setState(state);
+                top.copyBounds(compoundRect);
+                top.setCallback(this);
+                dr.mDrawableSizeTop = compoundRect.height();
+                dr.mDrawableWidthTop = compoundRect.width();
+            } else {
+                dr.mDrawableSizeTop = dr.mDrawableWidthTop = 0;
+            }
+
+            if (bottom != null) {
+                bottom.setState(state);
+                bottom.copyBounds(compoundRect);
+                bottom.setCallback(this);
+                dr.mDrawableSizeBottom = compoundRect.height();
+                dr.mDrawableWidthBottom = compoundRect.width();
+            } else {
+                dr.mDrawableSizeBottom = dr.mDrawableWidthBottom = 0;
+            }
+        }
+
+        resolveDrawables();
+        invalidate();
+        requestLayout();
+    }
+
+    /**
+     * Sets the Drawables (if any) to appear to the start of, above,
+     * to the end of, and below the text.  Use 0 if you do not
+     * want a Drawable there. The Drawables' bounds will be set to
+     * their intrinsic bounds.
+     *
+     * @param start Resource identifier of the start Drawable.
+     * @param top Resource identifier of the top Drawable.
+     * @param end Resource identifier of the end Drawable.
+     * @param bottom Resource identifier of the bottom Drawable.
+     *
+     * @attr ref android.R.styleable#TextView_drawableStart
+     * @attr ref android.R.styleable#TextView_drawableTop
+     * @attr ref android.R.styleable#TextView_drawableEnd
+     * @attr ref android.R.styleable#TextView_drawableBottom
+     *
+     * @hide
+     */
+    public void setCompoundDrawablesRelativeWithIntrinsicBounds(int start, int top, int end,
+            int bottom) {
+        resetResolvedDrawables();
+        final Resources resources = getContext().getResources();
+        setCompoundDrawablesRelativeWithIntrinsicBounds(
+                start != 0 ? resources.getDrawable(start) : null,
+                top != 0 ? resources.getDrawable(top) : null,
+                end != 0 ? resources.getDrawable(end) : null,
+                bottom != 0 ? resources.getDrawable(bottom) : null);
+    }
+
+    /**
+     * Sets the Drawables (if any) to appear to the start of, above,
+     * to the end of, and below the text.  Use null if you do not
+     * want a Drawable there. The Drawables' bounds will be set to
+     * their intrinsic bounds.
+     *
+     * @attr ref android.R.styleable#TextView_drawableStart
+     * @attr ref android.R.styleable#TextView_drawableTop
+     * @attr ref android.R.styleable#TextView_drawableEnd
+     * @attr ref android.R.styleable#TextView_drawableBottom
+     *
+     * @hide
+     */
+    public void setCompoundDrawablesRelativeWithIntrinsicBounds(Drawable start, Drawable top,
+            Drawable end, Drawable bottom) {
+
+        resetResolvedDrawables();
+        if (start != null) {
+            start.setBounds(0, 0, start.getIntrinsicWidth(), start.getIntrinsicHeight());
+        }
+        if (end != null) {
+            end.setBounds(0, 0, end.getIntrinsicWidth(), end.getIntrinsicHeight());
+        }
+        if (top != null) {
+            top.setBounds(0, 0, top.getIntrinsicWidth(), top.getIntrinsicHeight());
+        }
+        if (bottom != null) {
+            bottom.setBounds(0, 0, bottom.getIntrinsicWidth(), bottom.getIntrinsicHeight());
+        }
+        setCompoundDrawablesRelative(start, top, end, bottom);
+    }
+
+    /**
      * Returns drawables for the left, top, right, and bottom borders.
      */
     public Drawable[] getCompoundDrawables() {
@@ -1692,6 +1975,22 @@
     }
 
     /**
+     * Returns drawables for the start, top, end, and bottom borders.
+     *
+     * @hide
+     */
+    public Drawable[] getCompoundDrawablesRelative() {
+        final Drawables dr = mDrawables;
+        if (dr != null) {
+            return new Drawable[] {
+                dr.mDrawableStart, dr.mDrawableTop, dr.mDrawableEnd, dr.mDrawableBottom
+            };
+        } else {
+            return new Drawable[] { null, null, null, null };
+        }
+    }
+
+    /**
      * Sets the size of the padding between the compound drawables and
      * the text.
      *
@@ -2494,6 +2793,12 @@
             if (dr.mDrawableRight != null && dr.mDrawableRight.isStateful()) {
                 dr.mDrawableRight.setState(state);
             }
+            if (dr.mDrawableStart != null && dr.mDrawableStart.isStateful()) {
+                dr.mDrawableStart.setState(state);
+            }
+            if (dr.mDrawableEnd != null && dr.mDrawableEnd.isStateful()) {
+                dr.mDrawableEnd.setState(state);
+            }
         }
     }
 
@@ -3546,7 +3851,17 @@
         mErrorWasChanged = true;
         final Drawables dr = mDrawables;
         if (dr != null) {
-            setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon, dr.mDrawableBottom);
+            switch (getResolvedLayoutDirection()) {
+                default:
+                case LAYOUT_DIRECTION_LTR:
+                    setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon,
+                            dr.mDrawableBottom);
+                    break;
+                case LAYOUT_DIRECTION_RTL:
+                    setCompoundDrawables(icon, dr.mDrawableTop, dr.mDrawableRight,
+                            dr.mDrawableBottom);
+                    break;
+            }
         } else {
             setCompoundDrawables(null, null, icon, null);
         }
@@ -4048,6 +4363,9 @@
         if (mSelectionModifierCursorController != null) {
             observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
         }
+
+        // Resolve drawables as the layout direction has been resolved
+        resolveDrawables();
     }
 
     @Override
@@ -4077,6 +4395,8 @@
         }
 
         hideControllers();
+
+        resetResolvedDrawables();
     }
 
     @Override
@@ -4111,7 +4431,8 @@
         final boolean verified = super.verifyDrawable(who);
         if (!verified && mDrawables != null) {
             return who == mDrawables.mDrawableLeft || who == mDrawables.mDrawableTop ||
-                    who == mDrawables.mDrawableRight || who == mDrawables.mDrawableBottom;
+                    who == mDrawables.mDrawableRight || who == mDrawables.mDrawableBottom ||
+                    who == mDrawables.mDrawableStart || who == mDrawables.mDrawableEnd;
         }
         return verified;
     }
@@ -4132,6 +4453,12 @@
             if (mDrawables.mDrawableBottom != null) {
                 mDrawables.mDrawableBottom.jumpToCurrentState();
             }
+            if (mDrawables.mDrawableStart != null) {
+                mDrawables.mDrawableStart.jumpToCurrentState();
+            }
+            if (mDrawables.mDrawableEnd != null) {
+                mDrawables.mDrawableEnd.jumpToCurrentState();
+            }
         }
     }
 
@@ -4192,7 +4519,8 @@
         if (mDrawables != null) {
             final Drawables drawables = mDrawables;
             if (who == drawables.mDrawableLeft || who == drawables.mDrawableRight ||
-                who == drawables.mDrawableTop || who == drawables.mDrawableBottom) {
+                who == drawables.mDrawableTop || who == drawables.mDrawableBottom ||
+                who == drawables.mDrawableStart || who == drawables.mDrawableEnd) {
                 return getResolvedLayoutDirection();
             }
         }
@@ -4211,6 +4539,8 @@
                 if (dr.mDrawableTop != null) dr.mDrawableTop.mutate().setAlpha(alpha);
                 if (dr.mDrawableRight != null) dr.mDrawableRight.mutate().setAlpha(alpha);
                 if (dr.mDrawableBottom != null) dr.mDrawableBottom.mutate().setAlpha(alpha);
+                if (dr.mDrawableStart != null) dr.mDrawableStart.mutate().setAlpha(alpha);
+                if (dr.mDrawableEnd != null) dr.mDrawableEnd.mutate().setAlpha(alpha);
             }
             return true;
         }
@@ -10289,6 +10619,68 @@
         return (dir == Character.DIRECTIONALITY_LEFT_TO_RIGHT);
     }
 
+    /**
+     * Subclasses will need to override this method to implement their own way of resolving
+     * drawables depending on the layout direction.
+     *
+     * A call to the super method will be required from the subclasses implementation.
+     *
+     */
+    protected void resolveDrawables() {
+        // No need to resolve twice
+        if (bResolvedDrawables) {
+            return;
+        }
+        // No drawable to resolve
+        if (mDrawables == null) {
+            return;
+        }
+        // No relative drawable to resolve
+        if (mDrawables.mDrawableStart == null && mDrawables.mDrawableEnd == null) {
+            bResolvedDrawables = true;
+            return;
+        }
+
+        Drawables dr = mDrawables;
+        switch(getResolvedLayoutDirection()) {
+            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;
+        }
+        bResolvedDrawables = true;
+    }
+
+    protected void resetResolvedDrawables() {
+        bResolvedDrawables = false;
+    }
+
     @ViewDebug.ExportedProperty(category = "text")
     private CharSequence            mText;
     private CharSequence            mTransformed;
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9c2133f..cfc5041 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3015,6 +3015,10 @@
         <attr name="drawableLeft" format="reference|color" />
         <!-- The drawable to be drawn to the right of the text. -->
         <attr name="drawableRight" format="reference|color" />
+        <!-- The drawable to be drawn to the start of the text. -->
+        <attr name="drawableStart" format="reference|color" />
+        <!-- The drawable to be drawn to the end of the text. -->
+        <attr name="drawableEnd" format="reference|color" />
         <!-- The padding between the drawables and the text. -->
         <attr name="drawablePadding" format="dimension" />
         <!-- Extra spacing between lines of text. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f7701f2..6dedc83 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1826,4 +1826,7 @@
   <public type="color" name="holo_purple" />
   <public type="color" name="holo_blue_bright" />
 
+  <public type="attr" name="drawableStart" />
+  <public type="attr" name="drawableEnd" />
+
 </resources>
diff --git a/tests/BiDiTests/res/layout/textview_drawables_ltr.xml b/tests/BiDiTests/res/layout/textview_drawables_ltr.xml
new file mode 100644
index 0000000..88b13b7
--- /dev/null
+++ b/tests/BiDiTests/res/layout/textview_drawables_ltr.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/textview_drawables_ltr"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:layoutDirection="ltr">
+
+    <LinearLayout android:orientation="vertical"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent">
+
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawableLeft="@drawable/start"
+                  android:drawableRight="@drawable/end"
+                  android:drawablePadding="3dip"
+                />
+
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawableStart="@drawable/start"
+                  android:drawableEnd="@drawable/end"
+                  android:drawablePadding="3dip"
+                />
+
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawableLeft="@drawable/end"
+                  android:drawableStart="@drawable/start"
+                  android:drawableEnd="@drawable/end"
+                  android:drawablePadding="3dip"
+                />
+
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawableRight="@drawable/start"
+                  android:drawableStart="@drawable/start"
+                  android:drawableEnd="@drawable/end"
+                  android:drawablePadding="3dip"
+                />
+
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawableLeft="@drawable/end"
+                  android:drawableRight="@drawable/start"
+                  android:drawableStart="@drawable/start"
+                  android:drawableEnd="@drawable/end"
+                  android:drawablePadding="3dip"
+                />
+
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawableRight="@drawable/end"
+                  android:drawableStart="@drawable/start"
+                  android:drawablePadding="3dip"
+                />
+
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawableLeft="@drawable/start"
+                  android:drawableEnd="@drawable/end"
+                  android:drawablePadding="3dip"
+                />
+
+        <TextView android:id="@+id/textview_error"
+                  android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawablePadding="3dip"
+                />
+
+    </LinearLayout>
+
+</FrameLayout>
diff --git a/tests/BiDiTests/res/layout/textview_drawables_rtl.xml b/tests/BiDiTests/res/layout/textview_drawables_rtl.xml
new file mode 100644
index 0000000..7f47d5d
--- /dev/null
+++ b/tests/BiDiTests/res/layout/textview_drawables_rtl.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/textview_drawables_rtl"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:layoutDirection="rtl">
+
+    <LinearLayout android:orientation="vertical"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent">
+
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawableLeft="@drawable/end"
+                  android:drawableRight="@drawable/start"
+                  android:drawablePadding="3dip"
+                />
+
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawableStart="@drawable/start"
+                  android:drawableEnd="@drawable/end"
+                  android:drawablePadding="3dip"
+                />
+
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawableLeft="@drawable/start"
+                  android:drawableStart="@drawable/start"
+                  android:drawableEnd="@drawable/end"
+                  android:drawablePadding="3dip"
+                />
+
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawableRight="@drawable/end"
+                  android:drawableStart="@drawable/start"
+                  android:drawableEnd="@drawable/end"
+                  android:drawablePadding="3dip"
+                />
+
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawableLeft="@drawable/start"
+                  android:drawableRight="@drawable/end"
+                  android:drawableStart="@drawable/start"
+                  android:drawableEnd="@drawable/end"
+                  android:drawablePadding="3dip"
+                />
+
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawableLeft="@drawable/end"
+                  android:drawableStart="@drawable/start"
+                  android:drawablePadding="3dip"
+                />
+
+        <TextView android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawableRight="@drawable/start"
+                  android:drawableEnd="@drawable/end"
+                  android:drawablePadding="3dip"
+                />
+
+        <TextView android:id="@+id/textview_error"
+                  android:layout_height="wrap_content"
+                  android:layout_width="wrap_content"
+                  android:textSize="24dip"
+                  android:text="@string/textview_text"
+                  android:drawablePadding="3dip"
+                />
+
+    </LinearLayout>
+
+</FrameLayout>
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
index c033879..7002c41 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -134,6 +134,9 @@
         addItem(result, "TextDirection LTR", BiDiTestTextViewDirectionLtr.class, R.id.textview_direction_ltr);
         addItem(result, "TextDirection RTL", BiDiTestTextViewDirectionRtl.class, R.id.textview_direction_rtl);
 
+        addItem(result, "TextView Drawables LTR", BiDiTestTextViewDrawablesLtr.class, R.id.textview_drawables_ltr);
+        addItem(result, "TextView Drawables RTL", BiDiTestTextViewDrawablesRtl.class, R.id.textview_drawables_rtl);
+
         return result;
     }
 
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesLtr.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesLtr.java
new file mode 100644
index 0000000..a65d92d
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesLtr.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class BiDiTestTextViewDrawablesLtr extends Fragment {
+
+    private View currentView;
+    private TextView textViewError;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        currentView = inflater.inflate(R.layout.textview_drawables_ltr, container, false);
+        return currentView;
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+
+        textViewError = (TextView) currentView.findViewById(R.id.textview_error);
+        textViewError.setError("Error!!");
+    }
+}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesRtl.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesRtl.java
new file mode 100644
index 0000000..7b7e812
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesRtl.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class BiDiTestTextViewDrawablesRtl extends Fragment {
+
+    private View currentView;
+    private TextView textViewError;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        currentView = inflater.inflate(R.layout.textview_drawables_rtl, container, false);
+        return currentView;
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+
+        textViewError = (TextView) currentView.findViewById(R.id.textview_error);
+        textViewError.setError("Error!!");
+    }
+}