Support summary and restrict end items in RowView (views)

- Ensures icons or actions are shown at the end of the
  row but not both
- RowView will look for a summary slice when showing in
  small format

Test: manual with demo app + new builders from other CL
Bug: 68378574
Change-Id: I1142b5089e6e62c75b194c26f064512e302074b5
diff --git a/slices/core/src/main/java/androidx/app/slice/Slice.java b/slices/core/src/main/java/androidx/app/slice/Slice.java
index 8033bb7..ef0a05c 100644
--- a/slices/core/src/main/java/androidx/app/slice/Slice.java
+++ b/slices/core/src/main/java/androidx/app/slice/Slice.java
@@ -76,7 +76,7 @@
     @RestrictTo(Scope.LIBRARY)
     @StringDef({HINT_TITLE, HINT_LIST, HINT_LIST_ITEM, HINT_LARGE, HINT_ACTIONS, HINT_SELECTED,
             HINT_HORIZONTAL, HINT_NO_TINT, HINT_PARTIAL,
-            SliceHints.HINT_HIDDEN, SliceHints.SUBTYPE_TOGGLE})
+            SliceHints.HINT_SUMMARY, SliceHints.SUBTYPE_TOGGLE})
     public @interface SliceHint{ }
 
     private final SliceItem[] mItems;
diff --git a/slices/core/src/main/java/androidx/app/slice/SliceItem.java b/slices/core/src/main/java/androidx/app/slice/SliceItem.java
index e4412d1..51517e0 100644
--- a/slices/core/src/main/java/androidx/app/slice/SliceItem.java
+++ b/slices/core/src/main/java/androidx/app/slice/SliceItem.java
@@ -269,7 +269,7 @@
      * @hide
      */
     @RestrictTo(Scope.LIBRARY)
-    public boolean hasAnyHints(@Slice.SliceHint String[] hints) {
+    public boolean hasAnyHints(@Slice.SliceHint String... hints) {
         if (hints == null) return false;
         for (String hint : hints) {
             if (ArrayUtils.contains(mHints, hint)) {
diff --git a/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java b/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java
index 96e2c3f..34acf93 100644
--- a/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java
+++ b/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java
@@ -39,12 +39,10 @@
      * Key to retrieve an extra added to an intent when a control is changed.
      */
     public static final String EXTRA_TOGGLE_STATE = "android.app.slice.extra.TOGGLE_STATE";
+
     /**
-     * Hint to indicate that this content should not be shown in the
-     * {@link androidx.app.slice.widget.SliceView#MODE_SMALL}
-     * and {@link androidx.app.slice.widget.SliceView#MODE_LARGE} modes of SliceView.
-     * This content may be used to populate
-     * the {@link androidx.app.slice.widget.SliceView#MODE_SHORTCUT} format of the slice.
+     * Hint indicating this content should be shown instead of the normal content when the slice
+     * is in small format
      */
-    public static final String HINT_HIDDEN = "hidden";
+    public static final String HINT_SUMMARY = "summary";
 }
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/GridView.java b/slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java
similarity index 98%
rename from slices/view/src/main/java/androidx/app/slice/widget/GridView.java
rename to slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java
index edccc2c..531928f 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/GridView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java
@@ -62,7 +62,7 @@
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY)
 @TargetApi(24)
-public class GridView extends LinearLayout implements LargeSliceAdapter.SliceListView,
+public class GridRowView extends LinearLayout implements LargeSliceAdapter.SliceListView,
         View.OnClickListener, SliceView.SliceModeView {
 
     private static final String TAG = "GridView";
@@ -94,11 +94,11 @@
     private int mBigPictureHeight;
     private int mAllImagesHeight;
 
-    public GridView(Context context) {
+    public GridRowView(Context context) {
         this(context, null);
     }
 
-    public GridView(Context context, AttributeSet attrs) {
+    public GridRowView(Context context, AttributeSet attrs) {
         super(context, attrs);
         final Resources res = getContext().getResources();
         mIconSize = res.getDimensionPixelSize(R.dimen.abc_slice_icon_size);
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java b/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
index eb03d91..f77e1d9 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
@@ -24,6 +24,8 @@
 import static android.app.slice.SliceItem.FORMAT_SLICE;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
+import static androidx.app.slice.core.SliceHints.HINT_SUMMARY;
+
 import android.annotation.TargetApi;
 import android.content.Context;
 import android.support.annotation.RestrictTo;
@@ -101,7 +103,7 @@
             slice.getItems().forEach(new Consumer<SliceItem>() {
                 @Override
                 public void accept(SliceItem item) {
-                    if (item.hasHint(HINT_ACTIONS)) {
+                    if (item.hasAnyHints(HINT_ACTIONS, HINT_SUMMARY)) {
                         return;
                     } else if (FORMAT_COLOR.equals(item.getFormat())) {
                         return;
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/RowView.java b/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
index b903e3b..c516021 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
@@ -29,6 +29,7 @@
 import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
 
 import static androidx.app.slice.core.SliceHints.EXTRA_TOGGLE_STATE;
+import static androidx.app.slice.core.SliceHints.HINT_SUMMARY;
 
 import android.annotation.TargetApi;
 import android.app.PendingIntent;
@@ -76,9 +77,8 @@
 
     private int mIconSize;
     private int mPadding;
-
-    // If this is being used as a small template we don't allow a start item, for list items we do.
-    private boolean mAllowStartItem;
+    private boolean mInSmallMode;
+    private boolean mIsHeader;
 
     private LinearLayout mStartContainer;
     private LinearLayout mContent;
@@ -125,7 +125,8 @@
      */
     @Override
     public void setSliceItem(SliceItem slice, boolean isHeader) {
-        mAllowStartItem = !isHeader; // Headers don't show start items
+        mIsHeader = isHeader;
+        mInSmallMode = false;
         populateViews(slice, slice);
     }
 
@@ -134,16 +135,21 @@
      */
     @Override
     public void setSlice(Slice slice) {
-        mAllowStartItem = false;
+        mInSmallMode = true;
         Slice.Builder sb = new Slice.Builder(slice.getUri());
         sb.addSubSlice(slice);
         Slice parentSlice = sb.build();
-        populateViews(parentSlice.getItems().get(0), getHeaderItem(slice));
+        populateViews(parentSlice.getItems().get(0), getSummaryItem(slice));
     }
 
-    private SliceItem getHeaderItem(Slice slice) {
+    private SliceItem getSummaryItem(Slice slice) {
         List<SliceItem> items = slice.getItems();
-        // See if a header is specified
+        // See if a summary is specified
+        SliceItem summary = SliceQuery.find(slice, FORMAT_SLICE, HINT_SUMMARY, null);
+        if (summary != null) {
+            return summary;
+        }
+        // First fallback is using a header
         SliceItem header = SliceQuery.find(slice, FORMAT_SLICE, null, HINT_LIST_ITEM);
         if (header != null) {
             return header;
@@ -199,7 +205,7 @@
         SliceItem subTitle = null;
         ArrayList<SliceItem> endItems = new ArrayList<>();
 
-        // If the first item is an action let's check if it should be used to populate the content
+        // If the first item is an action check if it should be used to populate the content
         // or if it should be in the start position.
         SliceItem firstSlice = items.size() > 0 ? items.get(0) : null;
         if (firstSlice != null && FORMAT_ACTION.equals(firstSlice.getFormat())) {
@@ -255,7 +261,7 @@
                         : -1;
         // Populate main part of the template
         if (startItem != null) {
-            if (mAllowStartItem) {
+            if (!mIsHeader) {
                 startItem = addItem(startItem, color, mStartContainer, 0 /* padding */)
                         ? startItem
                         : null;
@@ -263,8 +269,8 @@
                     endItems.remove(startItem);
                 }
             } else {
-                startItem = null;
                 endItems.add(0, startItem);
+                startItem = null;
             }
         }
         mStartContainer.setVisibility(startItem != null ? View.VISIBLE : View.GONE);
@@ -290,14 +296,10 @@
                 .filter(new Predicate<SliceItem>() {
                     @Override
                     public boolean test(SliceItem item) {
-                        if (item == null) {
-                            return false;
-                        }
                         return FORMAT_ACTION.equals(item.getFormat())
                                 && SliceQuery.hasHints(item.getSlice(), SliceHints.SUBTYPE_TOGGLE);
                     }
-                })
-                .findFirst().orElse(null);
+                }).findFirst().orElse(null);
         if (toggleItem != null) {
             if (addToggle(toggleItem, color)) {
                 mDivider.setVisibility(mRowAction != null ? View.VISIBLE : View.GONE);
@@ -310,9 +312,9 @@
         int itemCount = 0;
         for (int i = 0; i < endItems.size(); i++) {
             SliceItem item = endItems.get(i);
-            if (item == null) {
-                // do nothing
-            } else if (itemCount <= MAX_END_ITEMS) {
+            // Only show one type of format at the end of the slice, use whatever is first
+            if (itemCount <= MAX_END_ITEMS
+                    && item.getFormat().equals(endItems.get(0).getFormat())) {
                 if (FORMAT_ACTION.equals(item.getFormat())
                         && itemCount == 0
                         && SliceQuery.hasHints(item.getSlice(), SliceHints.SUBTYPE_TOGGLE)
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java b/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
index 6a40898..b3a7f0c 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
@@ -260,7 +260,7 @@
             case MODE_SMALL:
                 // Check if it's horizontal
                 if (SliceQuery.hasHints(mCurrentSlice, HINT_HORIZONTAL)) {
-                    return new GridView(getContext());
+                    return new GridRowView(getContext());
                 } else {
                     return new RowView(getContext());
                 }
diff --git a/slices/view/src/main/res/layout/abc_slice_grid.xml b/slices/view/src/main/res/layout/abc_slice_grid.xml
index 7e264d0..890f77d 100644
--- a/slices/view/src/main/res/layout/abc_slice_grid.xml
+++ b/slices/view/src/main/res/layout/abc_slice_grid.xml
@@ -14,7 +14,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<androidx.app.slice.widget.GridView
+<androidx.app.slice.widget.GridRowView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -22,4 +22,4 @@
     android:gravity="center_vertical"
     android:background="?android:attr/activatedBackgroundIndicator"
     android:clipToPadding="false">
-</androidx.app.slice.widget.GridView>
+</androidx.app.slice.widget.GridRowView>