Show see more for grid row

* Add notion of see-more item to GridContent
* Update GridRowView to display see more
  - Use custom cell if available otherwise
  - For image only rows show an overlay “+n” on top of last item
  - Otherwise replace last item with circle-style “+n more”

* Adds examples to sample app and render tests
- Gallery slice demos overlay
- Subscription slice demos circle-style and custom

Test: ./gradlew slices-view:connectedCheck
Bug: 68378574
Change-Id: Ic74e2763d723da28f7eb8dcffa5a9d4173384cf1
diff --git a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
index 125d0db..0b945da 100644
--- a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
+++ b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
@@ -64,7 +64,7 @@
 
     public static final String[] URI_PATHS = {"message", "wifi", "note", "ride", "toggle",
             "toggle2", "contact", "gallery", "weather", "reservation", "loadlist", "loadlist2",
-            "loadgrid", "loadgrid2", "inputrange", "range", "contact2"};
+            "loadgrid", "loadgrid2", "inputrange", "range", "contact2", "subscription"};
 
     /**
      * @return Uri with the provided path
@@ -127,6 +127,8 @@
                 return createStarRatingInputRange(sliceUri);
             case "/range":
                 return createDownloadProgressRange(sliceUri);
+            case "/subscription":
+                return createCatSlice(sliceUri, false /* customSeeMore */);
         }
         throw new IllegalArgumentException("Unknown uri " + sliceUri);
     }
@@ -200,10 +202,50 @@
                                 LARGE_IMAGE))
                     .addCell(cb -> cb
                         .addImage(Icon.createWithResource(getContext(), R.drawable.slices_4),
-                                LARGE_IMAGE)))
+                                LARGE_IMAGE))
+                    .addSeeMoreAction(getBroadcastIntent(ACTION_TOAST, "see your gallery")))
                 .build();
     }
 
+    private Slice createCatSlice(Uri sliceUri, boolean customSeeMore) {
+        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        GridBuilder gb = new GridBuilder(b);
+        PendingIntent pi = getBroadcastIntent(ACTION_TOAST, "See cats you follow");
+        if (customSeeMore) {
+            GridBuilder.CellBuilder cb = new GridBuilder.CellBuilder(gb);
+            cb.addImage(Icon.createWithResource(getContext(), R.drawable.ic_right_caret),
+                    ICON_IMAGE);
+            cb.setContentIntent(pi);
+            cb.addTitleText("All cats");
+            gb.addSeeMoreCell(cb);
+        } else {
+            gb.addSeeMoreAction(pi);
+        }
+        gb.addCell(new GridBuilder.CellBuilder(gb)
+                    .addImage(Icon.createWithResource(getContext(), R.drawable.cat_1), SMALL_IMAGE)
+                    .addTitleText("Oreo"))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_2),
+                                SMALL_IMAGE)
+                        .addTitleText("Silver"))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_3),
+                                SMALL_IMAGE)
+                        .addTitleText("Drake"))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_5),
+                                SMALL_IMAGE)
+                        .addTitleText("Olive"))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_4),
+                                SMALL_IMAGE)
+                        .addTitleText("Lady Marmalade"))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_6),
+                                SMALL_IMAGE)
+                        .addTitleText("Grapefruit"));
+        return b.addGrid(gb).build();
+    }
 
     private Slice createContact2(Uri sliceUri) {
         ListBuilder b = new ListBuilder(getContext(), sliceUri);
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/cat_1.png b/samples/SupportSliceDemos/src/main/res/drawable/cat_1.png
new file mode 100644
index 0000000..64ea45f
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/cat_1.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/cat_2.png b/samples/SupportSliceDemos/src/main/res/drawable/cat_2.png
new file mode 100644
index 0000000..a1efd5d
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/cat_2.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/cat_3.png b/samples/SupportSliceDemos/src/main/res/drawable/cat_3.png
new file mode 100644
index 0000000..e1990a4
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/cat_3.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/cat_4.png b/samples/SupportSliceDemos/src/main/res/drawable/cat_4.png
new file mode 100644
index 0000000..a2c9af9
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/cat_4.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/cat_5.png b/samples/SupportSliceDemos/src/main/res/drawable/cat_5.png
new file mode 100644
index 0000000..9de2a8e
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/cat_5.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/cat_6.png b/samples/SupportSliceDemos/src/main/res/drawable/cat_6.png
new file mode 100644
index 0000000..5535c4b
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/cat_6.png
Binary files differ
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/GridBuilderListV1Impl.java b/slices/builders/src/main/java/androidx/slice/builders/impl/GridBuilderListV1Impl.java
index da33bfa..b8eebb9 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/GridBuilderListV1Impl.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/GridBuilderListV1Impl.java
@@ -95,7 +95,7 @@
      */
     @Override
     public void addCell(TemplateBuilderImpl builder) {
-        getBuilder().addSubSlice(builder.build());
+        getBuilder().addSubSlice(builder.getBuilder().addHints(HINT_LIST_ITEM).build());
     }
 
 
@@ -230,11 +230,11 @@
         public Slice build() {
             if (mContentIntent != null) {
                 return new Slice.Builder(getBuilder())
-                        .addHints(HINT_HORIZONTAL, HINT_LIST_ITEM)
+                        .addHints(HINT_HORIZONTAL)
                         .addAction(mContentIntent, getBuilder().build(), null)
                         .build();
             }
-            return getBuilder().addHints(HINT_HORIZONTAL, HINT_LIST_ITEM).build();
+            return getBuilder().addHints(HINT_HORIZONTAL).build();
         }
     }
 }
diff --git a/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java b/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java
index 31475d9..62b3610 100644
--- a/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java
+++ b/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java
@@ -53,7 +53,7 @@
     public static final String EXTRA_TOAST_MESSAGE = "com.example.androidx.extra.TOAST_MESSAGE";
 
     public static final String[] URI_PATHS = {"message", "wifi", "wifi2", "note", "ride", "toggle",
-            "toggle2", "contact", "gallery", "weather"};
+            "toggle2", "contact", "gallery", "subscription", "subscription2", "weather"};
 
     private final Context mContext;
 
@@ -97,6 +97,10 @@
                 return createContact(sliceUri);
             case "/gallery":
                 return createGallery(sliceUri);
+            case "/subscription":
+                return createSubSlice(sliceUri, false /* customSeeMore */);
+            case "/subscription2":
+                return createSubSlice(sliceUri, true /* customSeeMore */);
             case "/weather":
                 return createWeather(sliceUri);
         }
@@ -141,19 +145,71 @@
     private Slice createGallery(Uri sliceUri) {
         ListBuilder b = new ListBuilder(getContext(), sliceUri);
         GridBuilder gb = new GridBuilder(b);
-        return gb.addCell(new GridBuilder.CellBuilder(gb)
-                    .addImage(Icon.createWithResource(getContext(), R.drawable.slices_1),
-                            LARGE_IMAGE))
+        PendingIntent pi = getBroadcastIntent(ACTION_TOAST, "see more of your gallery");
+        gb.addSeeMoreAction(pi);
+        gb.addCell(new GridBuilder.CellBuilder(gb)
+                .addImage(Icon.createWithResource(getContext(), R.drawable.slices_1),
+                        LARGE_IMAGE))
                 .addCell(new GridBuilder.CellBuilder(gb)
-                    .addImage(Icon.createWithResource(getContext(), R.drawable.slices_2),
-                            LARGE_IMAGE))
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_2),
+                                LARGE_IMAGE))
                 .addCell(new GridBuilder.CellBuilder(gb)
-                    .addImage(Icon.createWithResource(getContext(), R.drawable.slices_3),
-                            LARGE_IMAGE))
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_3),
+                                LARGE_IMAGE))
                 .addCell(new GridBuilder.CellBuilder(gb)
-                    .addImage(Icon.createWithResource(getContext(), R.drawable.slices_4),
-                            LARGE_IMAGE))
-                .build();
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_4),
+                                LARGE_IMAGE))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_2),
+                                LARGE_IMAGE))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_3),
+                                LARGE_IMAGE))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_4),
+                                LARGE_IMAGE));
+        return b.addGrid(gb).build();
+    }
+
+    private Slice createSubSlice(Uri sliceUri, boolean customSeeMore) {
+        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        GridBuilder gb = new GridBuilder(b);
+        GridBuilder.CellBuilder cb = new GridBuilder.CellBuilder(gb);
+        PendingIntent pi = getBroadcastIntent(ACTION_TOAST, "See cats you follow");
+        if (customSeeMore) {
+            cb.addImage(Icon.createWithResource(getContext(), R.drawable.ic_right_caret),
+                    ICON_IMAGE);
+            cb.setContentIntent(pi);
+            cb.addText("All cats");
+            gb.addSeeMoreCell(cb);
+        } else {
+            gb.addSeeMoreAction(pi);
+        }
+        gb.addCell(new GridBuilder.CellBuilder(gb)
+                    .addImage(Icon.createWithResource(getContext(), R.drawable.cat_1),
+                            SMALL_IMAGE)
+                    .addTitleText("Oreo"))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_2),
+                                SMALL_IMAGE)
+                        .addTitleText("Silver"))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_3),
+                                SMALL_IMAGE)
+                        .addTitleText("Drake"))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_5),
+                                SMALL_IMAGE)
+                        .addTitleText("Olive"))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_4),
+                                SMALL_IMAGE)
+                        .addTitleText("Lady Marmalade"))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_6),
+                                SMALL_IMAGE)
+                        .addTitleText("Grapefruit"));
+        return b.addGrid(gb).build();
     }
 
     private Slice createContact(Uri sliceUri) {
diff --git a/slices/view/src/androidTest/res/drawable/cat_1.png b/slices/view/src/androidTest/res/drawable/cat_1.png
new file mode 100644
index 0000000..64ea45f
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/cat_1.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/cat_2.png b/slices/view/src/androidTest/res/drawable/cat_2.png
new file mode 100644
index 0000000..a1efd5d
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/cat_2.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/cat_3.png b/slices/view/src/androidTest/res/drawable/cat_3.png
new file mode 100644
index 0000000..e1990a4
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/cat_3.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/cat_4.png b/slices/view/src/androidTest/res/drawable/cat_4.png
new file mode 100644
index 0000000..a2c9af9
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/cat_4.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/cat_5.png b/slices/view/src/androidTest/res/drawable/cat_5.png
new file mode 100644
index 0000000..9de2a8e
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/cat_5.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/cat_6.png b/slices/view/src/androidTest/res/drawable/cat_6.png
new file mode 100644
index 0000000..5535c4b
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/cat_6.png
Binary files differ
diff --git a/slices/view/src/main/java/androidx/slice/widget/GridContent.java b/slices/view/src/main/java/androidx/slice/widget/GridContent.java
index 70bfb20..9493a14 100644
--- a/slices/view/src/main/java/androidx/slice/widget/GridContent.java
+++ b/slices/view/src/main/java/androidx/slice/widget/GridContent.java
@@ -17,6 +17,8 @@
 package androidx.slice.widget;
 
 import static android.app.slice.Slice.HINT_ACTIONS;
+import static android.app.slice.Slice.HINT_LIST_ITEM;
+import static android.app.slice.Slice.HINT_SEE_MORE;
 import static android.app.slice.Slice.HINT_SHORTCUT;
 import static android.app.slice.Slice.HINT_TITLE;
 import static android.app.slice.Slice.SUBTYPE_COLOR;
@@ -57,6 +59,7 @@
     private SliceItem mColorItem;
     private SliceItem mPrimaryAction;
     private ArrayList<CellContent> mGridContent = new ArrayList<>();
+    private SliceItem mSeeMoreItem;
     private int mMaxCellLineCount;
     private boolean mHasImage;
     private @ListBuilder.ImageMode int mLargestImageMode;
@@ -94,12 +97,16 @@
     private boolean populate(SliceItem gridItem) {
         reset();
         mColorItem = SliceQuery.findSubtype(gridItem, FORMAT_INT, SUBTYPE_COLOR);
+        mSeeMoreItem = SliceQuery.find(gridItem, null, HINT_SEE_MORE, null);
+        if (mSeeMoreItem != null && FORMAT_SLICE.equals(mSeeMoreItem.getFormat())) {
+            mSeeMoreItem = mSeeMoreItem.getSlice().getItems().get(0);
+        }
         String[] hints = new String[] {HINT_SHORTCUT, HINT_TITLE};
         mPrimaryAction = SliceQuery.find(gridItem, FORMAT_SLICE, hints,
                 new String[] {HINT_ACTIONS} /* nonHints */);
         mAllImages = true;
         if (FORMAT_SLICE.equals(gridItem.getFormat())) {
-            List<SliceItem> items = gridItem.getSlice().getItems();
+            List<SliceItem> items = gridItem.getSlice().getItems().get(0).getSlice().getItems();
             items = filterInvalidItems(items);
             // Check if it it's only one item that is a slice
             if (items.size() == 1 && items.get(0).getFormat().equals(FORMAT_SLICE)) {
@@ -154,6 +161,14 @@
     }
 
     /**
+     * @return the see more item to use when not all items in the grid can be displayed.
+     */
+    @Nullable
+    public SliceItem getSeeMoreItem() {
+        return mSeeMoreItem;
+    }
+
+    /**
      * @return whether this grid has content that is valid to display.
      */
     public boolean isValid() {
@@ -171,7 +186,8 @@
         List<SliceItem> filteredItems = new ArrayList<>();
         for (int i = 0; i < items.size(); i++) {
             SliceItem item = items.get(i);
-            if (!item.hasHint(HINT_SHORTCUT)) {
+            if (item.hasHint(HINT_LIST_ITEM) && !item.hasHint(HINT_SHORTCUT)
+                    && !item.hasHint(HINT_SEE_MORE)) {
                 filteredItems.add(item);
             }
         }
diff --git a/slices/view/src/main/java/androidx/slice/widget/GridRowView.java b/slices/view/src/main/java/androidx/slice/widget/GridRowView.java
index 51885ad..334f8a8 100644
--- a/slices/view/src/main/java/androidx/slice/widget/GridRowView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/GridRowView.java
@@ -21,6 +21,7 @@
 import static android.app.slice.Slice.HINT_TITLE;
 import static android.app.slice.SliceItem.FORMAT_ACTION;
 import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
 import static android.app.slice.SliceItem.FORMAT_TEXT;
 import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
@@ -31,7 +32,6 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.Color;
 import android.support.annotation.ColorInt;
 import android.support.annotation.RestrictTo;
 import android.util.AttributeSet;
@@ -165,9 +165,12 @@
             makeClickable(mViewContainer);
         }
         ArrayList<GridContent.CellContent> cells = gc.getGridContent();
+        boolean hasSeeMore = gc.getSeeMoreItem() != null;
         for (int i = 0; i < cells.size(); i++) {
             if (mViewContainer.getChildCount() >= MAX_CELLS) {
-                // TODO -- use item if it exists
+                if (hasSeeMore) {
+                    addSeeMoreCount(cells.size() - MAX_CELLS);
+                }
                 break;
             }
             addCell(cells.get(i), i, Math.min(cells.size(), MAX_CELLS));
@@ -175,22 +178,45 @@
     }
 
     private void addSeeMoreCount(int numExtra) {
-        View last = getChildAt(getChildCount() - 1);
-        FrameLayout frame = new FrameLayout(getContext());
-        frame.setLayoutParams(last.getLayoutParams());
+        // Remove last element
+        View last = mViewContainer.getChildAt(mViewContainer.getChildCount() - 1);
+        mViewContainer.removeView(last);
 
-        removeView(last);
-        frame.addView(last, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+        SliceItem seeMoreItem = mGridContent.getSeeMoreItem();
+        int index = mViewContainer.getChildCount();
+        int total = MAX_CELLS;
+        if ((FORMAT_SLICE.equals(seeMoreItem.getFormat())
+                || FORMAT_ACTION.equals(seeMoreItem.getFormat()))
+                && seeMoreItem.getSlice().getItems().size() > 0) {
+            // It's a custom see more cell, add it
+            addCell(new GridContent.CellContent(seeMoreItem), index, total);
+            return;
+        }
 
-        TextView v = new TextView(getContext());
-        v.setTextColor(Color.WHITE);
-        v.setBackgroundColor(0x4d000000);
-        v.setText(getResources().getString(R.string.abc_slice_more_content, numExtra));
-        v.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
-        v.setGravity(Gravity.CENTER);
-        frame.addView(v, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+        // Default see more, create it
+        LayoutInflater inflater = LayoutInflater.from(getContext());
+        TextView extraText;
+        ViewGroup seeMoreView;
+        if (mGridContent.isAllImages()) {
+            seeMoreView = (FrameLayout) inflater.inflate(R.layout.abc_slice_grid_see_more_overlay,
+                    mViewContainer, false);
+            seeMoreView.addView(last, 0, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+            extraText = seeMoreView.findViewById(R.id.text_see_more_count);
+        } else {
+            seeMoreView = (LinearLayout) inflater.inflate(
+                    R.layout.abc_slice_grid_see_more, mViewContainer, false);
+            extraText = seeMoreView.findViewById(R.id.text_see_more_count);
+        }
+        mViewContainer.addView(seeMoreView, new LinearLayout.LayoutParams(0, MATCH_PARENT, 1));
+        extraText.setText(getResources().getString(R.string.abc_slice_more_content, numExtra));
 
-        mViewContainer.addView(frame);
+        // Make it clickable
+        EventInfo info = new EventInfo(getMode(), EventInfo.ACTION_TYPE_BUTTON,
+                EventInfo.ROW_TYPE_GRID, mRowIndex);
+        info.setPosition(EventInfo.POSITION_CELL, index, total);
+        Pair<SliceItem, EventInfo> tagItem = new Pair<>(seeMoreItem, info);
+        seeMoreView.setTag(tagItem);
+        makeClickable(seeMoreView);
     }
 
     /**
@@ -257,6 +283,7 @@
                 MarginLayoutParams lp =
                         (LinearLayout.MarginLayoutParams) cellContainer.getLayoutParams();
                 lp.setMarginEnd(mGutter);
+                cellContainer.setLayoutParams(lp);
             }
             if (contentIntentItem != null) {
                 EventInfo info = new EventInfo(getMode(), EventInfo.ACTION_TYPE_BUTTON,
@@ -312,7 +339,7 @@
 
     private void makeClickable(View layout) {
         layout.setOnClickListener(this);
-        layout.setBackground(SliceViewUtil.getDrawable(getContext(),
+        layout.setForeground(SliceViewUtil.getDrawable(getContext(),
                 android.R.attr.selectableItemBackground));
     }
 
diff --git a/slices/view/src/main/res/drawable/abc_slice_see_more_bg.xml b/slices/view/src/main/res/drawable/abc_slice_see_more_bg.xml
new file mode 100644
index 0000000..8cc5cc2
--- /dev/null
+++ b/slices/view/src/main/res/drawable/abc_slice_see_more_bg.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 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.
+  -->
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+
+    <solid
+        android:color="#E5E5E5"/>
+</shape>
\ No newline at end of file
diff --git a/slices/view/src/main/res/layout/abc_slice_grid_see_more.xml b/slices/view/src/main/res/layout/abc_slice_grid_see_more.xml
new file mode 100644
index 0000000..17c1c0f
--- /dev/null
+++ b/slices/view/src/main/res/layout/abc_slice_grid_see_more.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 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.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:gravity="center_vertical"
+              android:layout_width="wrap_content"
+              android:layout_height="match_parent"
+              android:paddingEnd="@dimen/abc_slice_grid_gutter">
+
+    <TextView android:id="@+id/text_see_more_count"
+              android:layout_width="@dimen/abc_slice_small_image_size"
+              android:layout_height="@dimen/abc_slice_small_image_size"
+              android:gravity="center"
+              android:layout_gravity="center_horizontal"
+              android:textAppearance="?android:attr/textAppearanceMedium"
+              android:background="@drawable/abc_slice_see_more_bg"/>
+
+    <TextView android:id="@+id/text_see_more"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:gravity="center_horizontal"
+              android:text="@string/abc_slice_more"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/slices/view/src/main/res/layout/abc_slice_grid_see_more_overlay.xml b/slices/view/src/main/res/layout/abc_slice_grid_see_more_overlay.xml
new file mode 100644
index 0000000..8c8a86c
--- /dev/null
+++ b/slices/view/src/main/res/layout/abc_slice_grid_see_more_overlay.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 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:layout_width="match_parent"
+             android:layout_height="match_parent">
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:alpha="0.4"
+        android:background="?android:attr/colorForeground"/>
+
+    <TextView
+        android:id="@+id/text_see_more_count"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textColor="?android:attr/textColorPrimaryInverse"/>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/slices/view/src/main/res/values/strings.xml b/slices/view/src/main/res/values/strings.xml
index f73c6cc..8bdfa85 100644
--- a/slices/view/src/main/res/values/strings.xml
+++ b/slices/view/src/main/res/values/strings.xml
@@ -16,8 +16,10 @@
   -->
 
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- Format string for indicating there is more content in a slice view -->
+    <!-- Format string indicating the number of extra items that aren't being displayed. [CHAR LIMIT=none] -->
     <string name="abc_slice_more_content">+ <xliff:g id="number" example="5">%1$d</xliff:g></string>
+    <!-- Text indicating there is more content available that is not displayed. [CHAR LIMIT=10] -->
+    <string name="abc_slice_more">More</string>
     <!-- String to indicate there is more content to display in a list [CHAR LIMIT=none] -->
     <string name="abc_slice_show_more">Show more</string>
 </resources>
\ No newline at end of file