Add a 'gutter' attribute for specifying list item margins.

The gutter defaults to 'BOTH' and we also deprecate offsetScrollBar and
listEndMargin at the same time.

Test: build and run with a test app.
Bug: 69866647
Change-Id: I6b49a1b0b299c194643b288f52ccf2126ead2b9c
diff --git a/car/res/values/attrs.xml b/car/res/values/attrs.xml
index 0ba8f55..01ed95f 100644
--- a/car/res/values/attrs.xml
+++ b/car/res/values/attrs.xml
@@ -28,8 +28,24 @@
         <!-- Set to true/false to offset rows as they slide off screen. Defaults to true -->
         <attr name="offsetRows" format="boolean" />
         <!-- Whether or not to offset the list view by the width of scroll bar. Setting this to
-             true will ensure that any views within the list will not overlap the scroll bar. -->
+             true will ensure that any views within the list will not overlap the scroll bar.
+             Deprecated: use gutter instead. If gutter is specified, this value is ignored.-->
         <attr name="offsetScrollBar" format="boolean" />
+        <!-- Whether to include a gutter to the start, end or both sides of the list view items.
+             The gutter width will be the width of the scrollbar, and by default will be set to
+             both. -->
+        <attr name="gutter" format="enum">
+            <!-- No gutter on either side, the list view items will extend the full width of the
+                 PagedListView. -->
+            <enum name="none" value="0" />
+            <!-- Include a gutter on the start side only (i.e. the side with the scrollbar). -->
+            <enum name="start" value="1" />
+            <!-- Include a gutter on the end side only (i.e. the opposite side to the
+                 scrollbar). -->
+            <enum name="end" value="2" />
+            <!-- Include a gutter on both sides of the list view items. -->
+            <enum name="both" value="3" />
+        </attr>
         <!-- Whether to display the scrollbar or not. Defaults to true. -->
         <attr name="scrollBarEnabled" format="boolean" />
         <!-- Whether or not to show a diving line between each item of the list. -->
@@ -43,7 +59,8 @@
         <!-- A starting margin before the drawing of the dividing line. This margin will be an
              offset from the view specified by "alignDividerStartTo" if given. -->
         <attr name="dividerStartMargin" format="dimension" />
-        <!-- The width of the margin on the right side of the list -->
+        <!-- The width of the margin on the right side of the list.
+             Deprecated: use gutter instead. If gutter is specified, this value is ignored.-->
         <attr name="listEndMargin" format="dimension" />
         <!-- An optional spacing between items in the list -->
         <attr name="itemSpacing" format="dimension" />
diff --git a/car/src/main/java/android/support/car/widget/PagedListView.java b/car/src/main/java/android/support/car/widget/PagedListView.java
index 67a6247..d815f09 100644
--- a/car/src/main/java/android/support/car/widget/PagedListView.java
+++ b/car/src/main/java/android/support/car/widget/PagedListView.java
@@ -29,6 +29,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.support.annotation.IdRes;
+import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
@@ -119,6 +120,39 @@
     }
 
     /**
+     * The possible values for @{link #setGutter}. The default value is actually
+     * {@link Gutter#BOTH}.
+     */
+    @IntDef({
+            Gutter.NONE,
+            Gutter.START,
+            Gutter.END,
+            Gutter.BOTH,
+    })
+    public @interface Gutter {
+        /**
+         * No gutter on either side of the list items. The items will span the full width of the
+         * {@link PagedListView}.
+         */
+        int NONE = 0;
+
+        /**
+         * Include a gutter only on the start side (that is, the same side as the scroll bar).
+         */
+        int START = 1;
+
+        /**
+         * Include a gutter only on the end side (that is, the opposite side of the scroll bar).
+         */
+        int END = 2;
+
+        /**
+         * Include a gutter on both sides of the list items. This is the default behaviour.
+         */
+        int BOTH = 3;
+    }
+
+    /**
      * Interface for a {@link android.support.v7.widget.RecyclerView.Adapter} to set the position
      * offset for the adapter to load the data.
      *
@@ -167,14 +201,17 @@
         mRecyclerView.getRecycledViewPool().setMaxRecycledViews(0, 12);
         mRecyclerView.setItemAnimator(new CarItemAnimator(mLayoutManager));
 
-        boolean offsetScrollBar = a.getBoolean(R.styleable.PagedListView_offsetScrollBar, false);
-        if (offsetScrollBar) {
-            MarginLayoutParams params = (MarginLayoutParams) mRecyclerView.getLayoutParams();
-            params.setMarginStart(getResources().getDimensionPixelSize(
-                    R.dimen.car_margin));
-            params.setMarginEnd(
-                    a.getDimensionPixelSize(R.styleable.PagedListView_listEndMargin, 0));
-            mRecyclerView.setLayoutParams(params);
+        if (a.hasValue(R.styleable.PagedListView_gutter)) {
+            int gutter = a.getInt(R.styleable.PagedListView_gutter, Gutter.BOTH);
+            setGutter(gutter);
+        } else if (a.hasValue(R.styleable.PagedListView_offsetScrollBar)) {
+            boolean offsetScrollBar =
+                    a.getBoolean(R.styleable.PagedListView_offsetScrollBar, false);
+            if (offsetScrollBar) {
+                setGutter(Gutter.START);
+            }
+        } else {
+            setGutter(Gutter.BOTH);
         }
 
         if (a.getBoolean(R.styleable.PagedListView_showPagedListViewDivider, true)) {
@@ -286,6 +323,31 @@
         return mLayoutManager.getPosition(v);
     }
 
+    /**
+     * Set the gutter to the specified value.
+     *
+     * The gutter is the space to the start/end of the list view items and will be equal in size
+     * to the scroll bars. By default, there is a gutter to both the left and right of the list
+     * view items, to account for the scroll bar.
+     *
+     * @param gutter A {@link Gutter} value that identifies which sides to apply the gutter to.
+     */
+    public void setGutter(@Gutter int gutter) {
+        int startPadding = 0;
+        int endPadding = 0;
+        if ((gutter & Gutter.START) != 0) {
+            startPadding = getResources().getDimensionPixelSize(R.dimen.car_margin);
+        }
+        if ((gutter & Gutter.END) != 0) {
+            endPadding = getResources().getDimensionPixelSize(R.dimen.car_margin);
+        }
+        mRecyclerView.setPaddingRelative(startPadding, 0, endPadding, 0);
+
+        // If there's a gutter, set ClipToPadding to false so that CardView's shadow will still
+        // appear outside of the padding.
+        mRecyclerView.setClipToPadding(startPadding == 0 && endPadding == 0);
+    }
+
     @NonNull
     public CarRecyclerView getRecyclerView() {
         return mRecyclerView;