Fix for bug #8146846 Phone App should be mirrored for RTL languages

- add start/end aside left/right properties
- make default PhotoPosition depends on Locale layout direction
- add mirrored version of Drawables
- use android:textAlignment="viewStart" when needed on TextView

Change-Id: I0bf2fb83d94a3748d26d1825387b9b16830830a5
diff --git a/src/com/android/contacts/common/list/ContactEntryListFragment.java b/src/com/android/contacts/common/list/ContactEntryListFragment.java
index a6692b8..a8066b8 100644
--- a/src/com/android/contacts/common/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/common/list/ContactEntryListFragment.java
@@ -49,6 +49,8 @@
 import com.android.contacts.common.R;
 import com.android.contacts.common.preference.ContactsPreferences;
 
+import java.util.Locale;
+
 /**
  * Common base class for various contact-related list fragments.
  */
@@ -93,7 +95,7 @@
     private boolean mIncludeProfile;
     private boolean mSearchMode;
     private boolean mVisibleScrollbarEnabled;
-    private int mVerticalScrollbarPosition = View.SCROLLBAR_POSITION_RIGHT;
+    private int mVerticalScrollbarPosition = getDefaultVerticalScrollbarPosition();
     private String mQueryString;
     private int mDirectorySearchMode = DirectoryListLoader.SEARCH_MODE_NONE;
     private boolean mSelectionVisible;
@@ -147,6 +149,7 @@
             }
         }
     };
+    private int defaultVerticalScrollbarPosition;
 
     protected abstract View inflateView(LayoutInflater inflater, ViewGroup container);
     protected abstract T createListAdapter();
@@ -852,4 +855,16 @@
             reloadData();
         }
     };
+
+    private int getDefaultVerticalScrollbarPosition() {
+        final Locale locale = Locale.getDefault();
+        final int layoutDirection = TextUtils.getLayoutDirectionFromLocale(locale);
+        switch (layoutDirection) {
+            case View.LAYOUT_DIRECTION_RTL:
+                return View.SCROLLBAR_POSITION_LEFT;
+            case View.LAYOUT_DIRECTION_LTR:
+            default:
+                return View.SCROLLBAR_POSITION_RIGHT;
+        }
+    }
 }
diff --git a/src/com/android/contacts/common/list/ContactListItemView.java b/src/com/android/contacts/common/list/ContactListItemView.java
index 67d8030..c65a766 100644
--- a/src/com/android/contacts/common/list/ContactListItemView.java
+++ b/src/com/android/contacts/common/list/ContactListItemView.java
@@ -53,6 +53,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -111,13 +112,27 @@
 
     /**
      * Where to put contact photo. This affects the other Views' layout or look-and-feel.
+     *
+     * TODO: replace enum with int constants
      */
     public enum PhotoPosition {
         LEFT,
         RIGHT
     }
-    public static final PhotoPosition DEFAULT_PHOTO_POSITION = PhotoPosition.RIGHT;
-    private PhotoPosition mPhotoPosition = DEFAULT_PHOTO_POSITION;
+
+    static public final PhotoPosition getDefaultPhotoPosition(boolean opposite) {
+        final Locale locale = Locale.getDefault();
+        final int layoutDirection = TextUtils.getLayoutDirectionFromLocale(locale);
+        switch (layoutDirection) {
+            case View.LAYOUT_DIRECTION_RTL:
+                return (opposite ? PhotoPosition.RIGHT : PhotoPosition.LEFT);
+            case View.LAYOUT_DIRECTION_LTR:
+            default:
+                return (opposite ? PhotoPosition.LEFT : PhotoPosition.RIGHT);
+        }
+    }
+
+    private PhotoPosition mPhotoPosition = getDefaultPhotoPosition(false /* normal/non opposite */);
 
     // Header layout data
     private boolean mHeaderVisible;
@@ -259,7 +274,7 @@
                 R.styleable.ContactListItemView_list_item_label_width_weight,
                 mLabelViewWidthWeight);
 
-        setPadding(
+        setPaddingRelative(
                 a.getDimensionPixelOffset(
                         R.styleable.ContactListItemView_list_item_padding_left, 0),
                 a.getDimensionPixelOffset(
@@ -436,12 +451,14 @@
 
         // Add the height of the header if visible
         if (mHeaderVisible) {
+            final int headerWidth = specWidth -
+                    getPaddingLeft() - getPaddingRight() - mHeaderTextIndent;
             mHeaderTextView.measure(
-                    MeasureSpec.makeMeasureSpec(specWidth, MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(headerWidth, MeasureSpec.EXACTLY),
                     MeasureSpec.makeMeasureSpec(mHeaderBackgroundHeight, MeasureSpec.EXACTLY));
             if (mCountView != null) {
                 mCountView.measure(
-                        MeasureSpec.makeMeasureSpec(specWidth, MeasureSpec.AT_MOST),
+                        MeasureSpec.makeMeasureSpec(headerWidth, MeasureSpec.AT_MOST),
                         MeasureSpec.makeMeasureSpec(mHeaderBackgroundHeight, MeasureSpec.EXACTLY));
             }
             mHeaderBackgroundHeight = Math.max(mHeaderBackgroundHeight,
@@ -463,15 +480,13 @@
         int leftBound = getPaddingLeft();
         int rightBound = width - getPaddingRight();
 
-        if (isLayoutRtl()) {
-            mPhotoPosition = PhotoPosition.LEFT;
-        }
+        final boolean isLayoutRtl = isLayoutRtl();
 
         // Put the header in the top of the contact view (Text + underline view)
         if (mHeaderVisible) {
-            mHeaderTextView.layout(leftBound + mHeaderTextIndent,
+            mHeaderTextView.layout(isLayoutRtl ? leftBound : leftBound + mHeaderTextIndent,
                     0,
-                    rightBound,
+                    isLayoutRtl ? rightBound - mHeaderTextIndent : rightBound,
                     mHeaderBackgroundHeight);
             if (mCountView != null) {
                 mCountView.layout(rightBound - mCountView.getMeasuredWidth(),
@@ -529,6 +544,9 @@
                         rightBound,
                         photoTop + mPhotoViewHeight);
                 rightBound -= (mPhotoViewWidth + mGapBetweenImageAndText);
+            } else if (mKeepHorizontalPaddingForPhotoView) {
+                // Draw nothing but keep the padding.
+                rightBound -= (mPhotoViewWidth + mGapBetweenImageAndText);
             }
 
             // Add indent between left-most padding and texts.
@@ -551,22 +569,42 @@
         }
 
         // Presence and status
-        int statusLeftBound = leftBound;
-        if (isVisible(mPresenceIcon)) {
-            int iconWidth = mPresenceIcon.getMeasuredWidth();
-            mPresenceIcon.layout(
-                    leftBound,
-                    textTopBound,
-                    leftBound + iconWidth,
-                    textTopBound + mStatusTextViewHeight);
-            statusLeftBound += (iconWidth + mPresenceIconMargin);
-        }
+        if (isLayoutRtl) {
+            int statusRightBound = rightBound;
+            if (isVisible(mPresenceIcon)) {
+                int iconWidth = mPresenceIcon.getMeasuredWidth();
+                mPresenceIcon.layout(
+                        rightBound - iconWidth,
+                        textTopBound,
+                        rightBound,
+                        textTopBound + mStatusTextViewHeight);
+                statusRightBound -= (iconWidth + mPresenceIconMargin);
+            }
 
-        if (isVisible(mStatusView)) {
-            mStatusView.layout(statusLeftBound,
-                    textTopBound,
-                    rightBound,
-                    textTopBound + mStatusTextViewHeight);
+            if (isVisible(mStatusView)) {
+                mStatusView.layout(leftBound,
+                        textTopBound,
+                        statusRightBound,
+                        textTopBound + mStatusTextViewHeight);
+            }
+        } else {
+            int statusLeftBound = leftBound;
+            if (isVisible(mPresenceIcon)) {
+                int iconWidth = mPresenceIcon.getMeasuredWidth();
+                mPresenceIcon.layout(
+                        leftBound,
+                        textTopBound,
+                        leftBound + iconWidth,
+                        textTopBound + mStatusTextViewHeight);
+                statusLeftBound += (iconWidth + mPresenceIconMargin);
+            }
+
+            if (isVisible(mStatusView)) {
+                mStatusView.layout(statusLeftBound,
+                        textTopBound,
+                        rightBound,
+                        textTopBound + mStatusTextViewHeight);
+            }
         }
 
         if (isVisible(mStatusView) || isVisible(mPresenceIcon)) {
@@ -724,6 +762,7 @@
                 mHeaderTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mHeaderTextSize);
                 mHeaderTextView.setTypeface(mHeaderTextView.getTypeface(), Typeface.BOLD);
                 mHeaderTextView.setGravity(Gravity.CENTER_VERTICAL);
+                mHeaderTextView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
                 addView(mHeaderTextView);
             }
             if (mHeaderDivider == null) {
@@ -835,6 +874,8 @@
             // setActivated() call toward this whole item view.
             mNameTextView.setActivated(isActivated());
             mNameTextView.setGravity(Gravity.CENTER_VERTICAL);
+            mNameTextView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
+            mNameTextView.setId(R.id.cliv_name_textview);
             addView(mNameTextView);
         }
         return mNameTextView;
@@ -866,6 +907,7 @@
             mPhoneticNameTextView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
             mPhoneticNameTextView.setTypeface(mPhoneticNameTextView.getTypeface(), Typeface.BOLD);
             mPhoneticNameTextView.setActivated(isActivated());
+            mPhoneticNameTextView.setId(R.id.cliv_phoneticname_textview);
             addView(mPhoneticNameTextView);
         }
         return mPhoneticNameTextView;
@@ -898,11 +940,12 @@
             if (mPhotoPosition == PhotoPosition.LEFT) {
                 mLabelView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mCountViewTextSize);
                 mLabelView.setAllCaps(true);
-                mLabelView.setGravity(Gravity.RIGHT);
+                mLabelView.setGravity(Gravity.END);
             } else {
                 mLabelView.setTypeface(mLabelView.getTypeface(), Typeface.BOLD);
             }
             mLabelView.setActivated(isActivated());
+            mLabelView.setId(R.id.cliv_label_textview);
             addView(mLabelView);
         }
         return mLabelView;
@@ -911,7 +954,7 @@
     /**
      * Adds or updates a text view for the data element.
      */
-    public void setData(char[] text, int size) {
+    public void setData(char[] text, int size, int dataColumnIndex) {
         if (text == null || size == 0) {
             if (mDataView != null) {
                 mDataView.setVisibility(View.GONE);
@@ -920,6 +963,14 @@
             getDataView();
             setMarqueeText(mDataView, text, size);
             mDataView.setVisibility(VISIBLE);
+            // Check if this is a phone number. This code works also for the legacy phone number
+            // coming from LegacyPhoneNumberListAdapter.PHONE_NUMBER_COLUMN_INDEX because they are
+            // the exact same constant value (3)
+            if (dataColumnIndex == PhoneNumberListAdapter.PhoneQuery.PHONE_NUMBER) {
+                // We have a phone number as "mDataView" so make it always LTR and VIEW_START
+                mDataView.setTextDirection(View.TEXT_DIRECTION_LTR);
+                mDataView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
+            }
         }
     }
 
@@ -954,6 +1005,7 @@
             mDataView.setEllipsize(getTextEllipsis());
             mDataView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
             mDataView.setActivated(isActivated());
+            mDataView.setId(R.id.cliv_data_view);
             addView(mDataView);
         }
         return mDataView;
@@ -1000,6 +1052,7 @@
             mStatusView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
             mStatusView.setTextColor(mSecondaryTextColor);
             mStatusView.setActivated(isActivated());
+            mStatusView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
             addView(mStatusView);
         }
         return mStatusView;
@@ -1336,7 +1389,7 @@
      */
     public void showData(Cursor cursor, int dataColumnIndex) {
         cursor.copyStringToBuffer(dataColumnIndex, mDataBuffer);
-        setData(mDataBuffer.data, mDataBuffer.sizeCopied);
+        setData(mDataBuffer.data, mDataBuffer.sizeCopied, dataColumnIndex);
     }
 
     public void setActivatedStateSupported(boolean flag) {
diff --git a/src/com/android/contacts/common/list/ContactListPinnedHeaderView.java b/src/com/android/contacts/common/list/ContactListPinnedHeaderView.java
index 9aa9a9b..bdefd4c 100644
--- a/src/com/android/contacts/common/list/ContactListPinnedHeaderView.java
+++ b/src/com/android/contacts/common/list/ContactListPinnedHeaderView.java
@@ -87,6 +87,7 @@
         mHeaderTextView.setTypeface(mHeaderTextView.getTypeface(), Typeface.BOLD);
         mHeaderTextView.setGravity(Gravity.CENTER_VERTICAL);
         mHeaderTextView.setAllCaps(true);
+        mHeaderTextView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
         addView(mHeaderTextView);
         mHeaderDivider = new View(mContext);
         mHeaderDivider.setBackgroundColor(mHeaderUnderlineColor);
@@ -115,17 +116,40 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         int width = right - left;
 
+        final int leftHeaderTextView;
+        final int rightHeaderTextView;
+        final int topTextView = 0;
+        final int bottomTextView = mHeaderBackgroundHeight;
+
+        int leftCountTextView = 0;
+        int rightCountTextView = 0;
+
+        if (isLayoutRtl()) {
+            rightHeaderTextView = width - mPaddingRight - mHeaderTextIndent;
+            leftHeaderTextView = rightHeaderTextView - mHeaderTextView.getMeasuredWidth();
+
+            leftCountTextView = mHeaderTextIndent + mPaddingLeft;
+            rightCountTextView = mCountTextView.getMeasuredWidth() + leftCountTextView;
+        } else {
+            leftHeaderTextView = mHeaderTextIndent + mPaddingLeft;
+            rightHeaderTextView = mHeaderTextView.getMeasuredWidth() + leftHeaderTextView;
+
+            // Order of statements matters
+            rightCountTextView = width - mPaddingRight;
+            leftCountTextView = rightCountTextView - mCountTextView.getMeasuredWidth();
+        }
+
         // Take into account left and right padding when laying out the below views.
-        mHeaderTextView.layout(mHeaderTextIndent + mPaddingLeft,
-                0,
-                mHeaderTextView.getMeasuredWidth() + mHeaderTextIndent + mPaddingLeft,
-                mHeaderBackgroundHeight);
+        mHeaderTextView.layout(leftHeaderTextView,
+                topTextView,
+                rightHeaderTextView,
+                bottomTextView);
 
         if (isViewMeasurable(mCountTextView)) {
-            mCountTextView.layout(width - mPaddingRight - mCountTextView.getMeasuredWidth(),
-                    0,
-                    width - mPaddingRight,
-                    mHeaderBackgroundHeight);
+            mCountTextView.layout(leftCountTextView,
+                    topTextView,
+                    rightCountTextView,
+                    bottomTextView);
         }
 
         mHeaderDivider.layout(mPaddingLeft,
diff --git a/src/com/android/contacts/common/list/ContactTileAdapter.java b/src/com/android/contacts/common/list/ContactTileAdapter.java
index 16dd604..557ebff 100644
--- a/src/com/android/contacts/common/list/ContactTileAdapter.java
+++ b/src/com/android/contacts/common/list/ContactTileAdapter.java
@@ -556,7 +556,7 @@
                 case ViewTypes.STARRED_PHONE:
                 case ViewTypes.STARRED:
                     // Setting divider visibilities
-                    contactTile.setPadding(0, 0,
+                    contactTile.setPaddingRelative(0, 0,
                             childIndex >= mColumnCount - 1 ? 0 : mPaddingInPixels,
                             isLastRow ? 0 : mPaddingInPixels);
                     break;
diff --git a/src/com/android/contacts/common/list/PhoneNumberPickerFragment.java b/src/com/android/contacts/common/list/PhoneNumberPickerFragment.java
index ec0eee9..4f99e62 100644
--- a/src/com/android/contacts/common/list/PhoneNumberPickerFragment.java
+++ b/src/com/android/contacts/common/list/PhoneNumberPickerFragment.java
@@ -62,7 +62,7 @@
     private boolean mUseCallableUri;
 
     private ContactListItemView.PhotoPosition mPhotoPosition =
-            ContactListItemView.DEFAULT_PHOTO_POSITION;
+            ContactListItemView.getDefaultPhotoPosition(false /* normal/non opposite */);
 
     private class FilterHeaderClickListener implements OnClickListener {
         @Override
diff --git a/src/com/android/contacts/common/list/PinnedHeaderListView.java b/src/com/android/contacts/common/list/PinnedHeaderListView.java
index d006f4b..3f207a5 100644
--- a/src/com/android/contacts/common/list/PinnedHeaderListView.java
+++ b/src/com/android/contacts/common/list/PinnedHeaderListView.java
@@ -103,7 +103,7 @@
     private int mAnimationDuration = DEFAULT_ANIMATION_DURATION;
     private boolean mAnimating;
     private long mAnimationTargetTime;
-    private int mHeaderPaddingLeft;
+    private int mHeaderPaddingStart;
     private int mHeaderWidth;
 
     public PinnedHeaderListView(Context context) {
@@ -123,8 +123,8 @@
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
-        mHeaderPaddingLeft = getPaddingLeft();
-        mHeaderWidth = r - l - mHeaderPaddingLeft - getPaddingRight();
+        mHeaderPaddingStart = getPaddingStart();
+        mHeaderWidth = r - l - mHeaderPaddingStart - getPaddingEnd();
     }
 
     public void setPinnedHeaderAnimationDuration(int duration) {
@@ -170,6 +170,7 @@
                     mHeaders[i] = new PinnedHeader();
                 }
                 mHeaders[i].view = mAdapter.getPinnedHeaderView(i, mHeaders[i].view, this);
+                mHeaders[i].view.setLayoutDirection(getLayoutDirection());
             }
 
             mAnimationTargetTime = System.currentTimeMillis() + mAnimationDuration;
@@ -511,7 +512,9 @@
         if (header.visible) {
             View view = header.view;
             int saveCount = canvas.save();
-            canvas.translate(mHeaderPaddingLeft, header.y);
+            canvas.translate(isLayoutRtl() ?
+                    getWidth() - mHeaderPaddingStart - mHeaderWidth : mHeaderPaddingStart,
+                    header.y);
             if (header.state == FADING) {
                 mBounds.set(0, 0, mHeaderWidth, view.getHeight());
                 canvas.saveLayerAlpha(mBounds, header.alpha, Canvas.ALL_SAVE_FLAG);