ListContent.java revision 92952f5bbd2b743091af437767b0b48e48d292b5
16b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor/*
26b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor * Copyright 2017 The Android Open Source Project
36b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor *
46b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor * Licensed under the Apache License, Version 2.0 (the "License");
56b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor * you may not use this file except in compliance with the License.
66b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor * You may obtain a copy of the License at
76b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor *
86b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor *      http://www.apache.org/licenses/LICENSE-2.0
96b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor *
106b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor * Unless required by applicable law or agreed to in writing, software
116b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor * distributed under the License is distributed on an "AS IS" BASIS,
126b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor * See the License for the specific language governing permissions and
146b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor * limitations under the License.
156b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor */
166b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
1785ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikaspackage androidx.slice.widget;
186b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
196b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellorimport static android.app.slice.Slice.HINT_ACTIONS;
208a2763f580c71e17a0b13e682c73012e902b4232Mady Mellorimport static android.app.slice.Slice.HINT_HORIZONTAL;
216b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellorimport static android.app.slice.Slice.HINT_LIST_ITEM;
2253380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellorimport static android.app.slice.Slice.HINT_SEE_MORE;
23af76b3bd62a6b218bb44917b1dddfa1ee4803149Mady Mellorimport static android.app.slice.Slice.HINT_SHORTCUT;
246b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellorimport static android.app.slice.Slice.SUBTYPE_COLOR;
256b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellorimport static android.app.slice.SliceItem.FORMAT_ACTION;
266b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellorimport static android.app.slice.SliceItem.FORMAT_INT;
276b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellorimport static android.app.slice.SliceItem.FORMAT_SLICE;
28968346929453133f937381a2e685bc4e47788e2cMady Mellorimport static android.app.slice.SliceItem.FORMAT_TEXT;
296b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
300707dbe9fa3225cc921a2305a611272f0dee1ca8Mady Mellorimport static androidx.slice.core.SliceHints.HINT_KEYWORDS;
3163fb9955b209f1bb9d19e41df9784bfbdf63defeMady Mellorimport static androidx.slice.core.SliceHints.HINT_LAST_UPDATED;
3263fb9955b209f1bb9d19e41df9784bfbdf63defeMady Mellorimport static androidx.slice.core.SliceHints.HINT_TTL;
33bb51b5909dd8d5b233cd675fbc6fe74c42f48d3cMady Mellor
348a2763f580c71e17a0b13e682c73012e902b4232Mady Mellorimport android.content.Context;
356b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
36bb51b5909dd8d5b233cd675fbc6fe74c42f48d3cMady Mellorimport androidx.annotation.NonNull;
37bb51b5909dd8d5b233cd675fbc6fe74c42f48d3cMady Mellorimport androidx.annotation.Nullable;
38bb51b5909dd8d5b233cd675fbc6fe74c42f48d3cMady Mellorimport androidx.annotation.RestrictTo;
3985ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikasimport androidx.slice.Slice;
4085ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikasimport androidx.slice.SliceItem;
41e7f1c6cf75ce36c633075445bd676572a9fe0f47Mady Mellorimport androidx.slice.SliceMetadata;
42ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellorimport androidx.slice.core.SliceAction;
43ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellorimport androidx.slice.core.SliceActionImpl;
4485ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikasimport androidx.slice.core.SliceQuery;
456b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
46c50cc30733ad1058f98523c25f7413745638332aMady Mellorimport java.util.ArrayList;
47c50cc30733ad1058f98523c25f7413745638332aMady Mellorimport java.util.List;
48c50cc30733ad1058f98523c25f7413745638332aMady Mellor
496b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor/**
506b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor * Extracts information required to present content in a list format from a slice.
516b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor * @hide
526b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor */
536b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
546b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellorpublic class ListContent {
556b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
56968346929453133f937381a2e685bc4e47788e2cMady Mellor    private SliceItem mHeaderItem;
576b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    private SliceItem mColorItem;
5853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    private SliceItem mSeeMoreItem;
596b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    private ArrayList<SliceItem> mRowItems = new ArrayList<>();
60968346929453133f937381a2e685bc4e47788e2cMady Mellor    private List<SliceItem> mSliceActions;
618a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    private Context mContext;
626b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
638a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    public ListContent(Context context, Slice slice) {
648a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor        mContext = context;
656b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        populate(slice);
666b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
676b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
686b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    /**
696b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor     * @return whether this row has content that is valid to display.
706b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor     */
718a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    private boolean populate(Slice slice) {
726b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        mColorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
73968346929453133f937381a2e685bc4e47788e2cMady Mellor        // Find slice actions
74e7f1c6cf75ce36c633075445bd676572a9fe0f47Mady Mellor        mSliceActions = SliceMetadata.getSliceActions(slice);
75968346929453133f937381a2e685bc4e47788e2cMady Mellor        // Find header
76968346929453133f937381a2e685bc4e47788e2cMady Mellor        mHeaderItem = findHeaderItem(slice);
77968346929453133f937381a2e685bc4e47788e2cMady Mellor        if (mHeaderItem != null) {
78968346929453133f937381a2e685bc4e47788e2cMady Mellor            mRowItems.add(mHeaderItem);
79968346929453133f937381a2e685bc4e47788e2cMady Mellor        }
8053380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        mSeeMoreItem = getSeeMoreItem(slice);
816b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        // Filter + create row items
826b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        List<SliceItem> children = slice.getItems();
836b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        for (int i = 0; i < children.size(); i++) {
846b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor            final SliceItem child = children.get(i);
856b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor            final String format = child.getFormat();
860707dbe9fa3225cc921a2305a611272f0dee1ca8Mady Mellor            boolean isNonRowContent = child.hasAnyHints(HINT_ACTIONS, HINT_SEE_MORE, HINT_KEYWORDS,
8763fb9955b209f1bb9d19e41df9784bfbdf63defeMady Mellor                    HINT_TTL, HINT_LAST_UPDATED);
8863fb9955b209f1bb9d19e41df9784bfbdf63defeMady Mellor            if (!isNonRowContent && (FORMAT_ACTION.equals(format) || FORMAT_SLICE.equals(format))) {
89968346929453133f937381a2e685bc4e47788e2cMady Mellor                if (mHeaderItem == null && !child.hasHint(HINT_LIST_ITEM)) {
90968346929453133f937381a2e685bc4e47788e2cMady Mellor                    mHeaderItem = child;
916b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor                    mRowItems.add(0, child);
92968346929453133f937381a2e685bc4e47788e2cMady Mellor                } else if (child.hasHint(HINT_LIST_ITEM)) {
936b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor                    mRowItems.add(child);
946b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor                }
956b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor            }
966b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        }
97968346929453133f937381a2e685bc4e47788e2cMady Mellor        // Ensure we have something for the header -- use first row
98968346929453133f937381a2e685bc4e47788e2cMady Mellor        if (mHeaderItem == null && mRowItems.size() >= 1) {
99968346929453133f937381a2e685bc4e47788e2cMady Mellor            mHeaderItem = mRowItems.get(0);
100968346929453133f937381a2e685bc4e47788e2cMady Mellor        }
1016b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        return isValid();
1026b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
1036b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
1046b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    /**
1058dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor     * Expects the provided list of items to be filtered (i.e. only things that can be turned into
1068dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor     * GridContent or RowContent) and in order (i.e. first item could be a header).
1078dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor     *
10853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     * @return the total height of all the rows contained in the provided list.
1098a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor     */
11053380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    public static int getListHeight(Context context, List<SliceItem> listItems) {
1118a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor        int height = 0;
1128dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor        boolean hasRealHeader = false;
1138dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor        if (listItems.size() > 0) {
1148dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor            SliceItem maybeHeader = listItems.get(0);
1158dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor            hasRealHeader = !maybeHeader.hasAnyHints(HINT_LIST_ITEM, HINT_HORIZONTAL);
1168dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor        }
11753380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        for (int i = 0; i < listItems.size(); i++) {
1188dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor            height += getHeight(context, listItems.get(i), i == 0 && hasRealHeader /* isHeader */);
11953380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        }
12053380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        return height;
12153380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    }
12253380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor
12353380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    /**
12453380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     * Returns a list of items that can be displayed in the provided height. If this list
12553380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     * has a {@link #getSeeMoreItem()} this will be returned in the list if appropriate.
12653380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     *
12753380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     * @param height the height to restrict the items, -1 to use default sizings for non-scrolling
12853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     *               templates.
12953380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     * @return the list of items that can be displayed in the provided  height.
13053380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     */
13153380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    @NonNull
13253380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    public List<SliceItem> getItemsForNonScrollingList(int height) {
13353380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        ArrayList<SliceItem> visibleItems = new ArrayList<>();
13453380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        if (mRowItems == null || mRowItems.size() == 0) {
13553380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor            return visibleItems;
13653380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        }
13753380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        final int idealItemCount = hasHeader() ? 4 : 3;
13853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        final int minItemCount = hasHeader() ? 2 : 1;
13953380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        int visibleHeight = 0;
14053380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        // Need to show see more
14153380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        if (mSeeMoreItem != null) {
14253380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor            RowContent rc = new RowContent(mContext, mSeeMoreItem, false /* isHeader */);
14353380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor            visibleHeight += rc.getActualHeight();
14453380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        }
1458a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor        for (int i = 0; i < mRowItems.size(); i++) {
14653380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor            int itemHeight = getHeight(mContext, mRowItems.get(i), i == 0 /* isHeader */);
14753380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor            if ((height == -1 && i > idealItemCount)
14853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor                    || (height > 0 && visibleHeight + itemHeight > height)) {
14953380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor                break;
1508a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor            } else {
15153380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor                visibleHeight += itemHeight;
15253380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor                visibleItems.add(mRowItems.get(i));
1538a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor            }
1548a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor        }
15553380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        if (mSeeMoreItem != null && visibleItems.size() >= minItemCount) {
15653380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor            // Only add see more if we're at least showing one item and it's not the header
15753380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor            visibleItems.add(mSeeMoreItem);
15853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        }
15953380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        if (visibleItems.size() == 0) {
16053380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor            // Didn't have enough space to show anything; should still show something
16153380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor            visibleItems.add(mRowItems.get(0));
16253380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        }
16353380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        return visibleItems;
16453380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    }
16553380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor
16653380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    private static int getHeight(Context context, SliceItem item, boolean isHeader) {
16753380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        if (item.hasHint(HINT_HORIZONTAL)) {
16853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor            GridContent gc = new GridContent(context, item);
16953380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor            return gc.getActualHeight();
17053380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        } else {
17153380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor            RowContent rc = new RowContent(context, item, isHeader);
17253380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor            return rc.getActualHeight();
17353380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        }
1748a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    }
1758a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor
1768a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    /**
1776b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor     * @return whether this list has content that is valid to display.
1786b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor     */
1796b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    public boolean isValid() {
180968346929453133f937381a2e685bc4e47788e2cMady Mellor        return mRowItems.size() > 0;
1816b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
1826b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
1836b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    @Nullable
1846b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    public SliceItem getColorItem() {
1856b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        return mColorItem;
1866b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
1876b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
1886b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    @Nullable
189968346929453133f937381a2e685bc4e47788e2cMady Mellor    public SliceItem getHeaderItem() {
190968346929453133f937381a2e685bc4e47788e2cMady Mellor        return mHeaderItem;
191968346929453133f937381a2e685bc4e47788e2cMady Mellor    }
192968346929453133f937381a2e685bc4e47788e2cMady Mellor
193968346929453133f937381a2e685bc4e47788e2cMady Mellor    @Nullable
194968346929453133f937381a2e685bc4e47788e2cMady Mellor    public List<SliceItem> getSliceActions() {
195968346929453133f937381a2e685bc4e47788e2cMady Mellor        return mSliceActions;
1966b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
1976b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
19853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    @Nullable
19953380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    public SliceItem getSeeMoreItem() {
20053380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        return mSeeMoreItem;
20153380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    }
20253380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor
2036b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    public ArrayList<SliceItem> getRowItems() {
2046b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        return mRowItems;
2056b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
2066b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
2076b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    /**
208968346929453133f937381a2e685bc4e47788e2cMady Mellor     * @return whether this list has an explicit header (i.e. row item without HINT_LIST_ITEM)
2096b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor     */
2106b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    public boolean hasHeader() {
211968346929453133f937381a2e685bc4e47788e2cMady Mellor        return mHeaderItem != null && isValidHeader(mHeaderItem);
2126b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
2136b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
214c50cc30733ad1058f98523c25f7413745638332aMady Mellor    /**
215ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor     * @return the type of template that the header represents.
216ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor     */
217ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor    public int getHeaderTemplateType() {
2186975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor        return getRowType(mContext, mHeaderItem, true, mSliceActions);
2196975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor    }
2206975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor
2216975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor    /**
2226975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor     * The type of template that the provided row item represents.
2236975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor     *
2246975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor     * @param context context used for this slice.
2256975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor     * @param rowItem the row item to determine the template type of.
2266975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor     * @param isHeader whether this row item is used as a header.
2276975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor     * @param actions the actions associated with this slice, only matter if this row is the header.
2286975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor     * @return the type of template the provided row item represents.
2296975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor     */
2306975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor    public static int getRowType(Context context, SliceItem rowItem, boolean isHeader,
2316975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor                                 List<SliceItem> actions) {
2326975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor        if (rowItem != null) {
2336975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor            if (rowItem.hasHint(HINT_HORIZONTAL)) {
234ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                return EventInfo.ROW_TYPE_GRID;
235ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor            } else {
2366975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor                RowContent rc = new RowContent(context, rowItem, isHeader);
237ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                SliceItem actionItem = rc.getPrimaryAction();
238ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                SliceAction primaryAction = null;
239ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                if (actionItem != null) {
240ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                    primaryAction = new SliceActionImpl(actionItem);
241ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                }
242ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                if (rc.getRange() != null) {
243ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                    return FORMAT_ACTION.equals(rc.getRange().getFormat())
244ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                            ? EventInfo.ROW_TYPE_SLIDER
245ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                            : EventInfo.ROW_TYPE_PROGRESS;
246ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                } else if (primaryAction != null && primaryAction.isToggle()) {
247ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                    return EventInfo.ROW_TYPE_TOGGLE;
2486975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor                } else if (isHeader && actions != null) {
2496975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor                    for (int i = 0; i < actions.size(); i++) {
2506975e4e9eba6772c9d7d38374109a90dd4f390cdMady Mellor                        if (new SliceActionImpl(actions.get(i)).isToggle()) {
251ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                            return EventInfo.ROW_TYPE_TOGGLE;
252ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                        }
253ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                    }
254ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                    return EventInfo.ROW_TYPE_LIST;
255ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                } else {
256ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                    return rc.getToggleItems().size() > 0
257ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                            ? EventInfo.ROW_TYPE_TOGGLE
258ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                            : EventInfo.ROW_TYPE_LIST;
259ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                }
260ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor            }
261ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor        }
262ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor        return EventInfo.ROW_TYPE_LIST;
263ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor    }
264ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor
265ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor    /**
266c50cc30733ad1058f98523c25f7413745638332aMady Mellor     * @return the primary action for this list; i.e. action on the header or first row.
267c50cc30733ad1058f98523c25f7413745638332aMady Mellor     */
268c50cc30733ad1058f98523c25f7413745638332aMady Mellor    @Nullable
269c50cc30733ad1058f98523c25f7413745638332aMady Mellor    public SliceItem getPrimaryAction() {
270ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor        if (mHeaderItem != null) {
271ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor            if (mHeaderItem.hasHint(HINT_HORIZONTAL)) {
272ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                GridContent gc = new GridContent(mContext, mHeaderItem);
273ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                return gc.getContentIntent();
274ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor            } else {
275ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                RowContent rc = new RowContent(mContext, mHeaderItem, false);
276ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                return rc.getPrimaryAction();
277ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor            }
278ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor        }
279ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor        return null;
280c50cc30733ad1058f98523c25f7413745638332aMady Mellor    }
281c50cc30733ad1058f98523c25f7413745638332aMady Mellor
282968346929453133f937381a2e685bc4e47788e2cMady Mellor    @Nullable
283968346929453133f937381a2e685bc4e47788e2cMady Mellor    private static SliceItem findHeaderItem(@NonNull Slice slice) {
284968346929453133f937381a2e685bc4e47788e2cMady Mellor        // See if header is specified
285bb51b5909dd8d5b233cd675fbc6fe74c42f48d3cMady Mellor        String[] nonHints = new String[] {HINT_LIST_ITEM, HINT_SHORTCUT, HINT_ACTIONS,
2860707dbe9fa3225cc921a2305a611272f0dee1ca8Mady Mellor                HINT_KEYWORDS, HINT_TTL, HINT_LAST_UPDATED};
287b794b5b0f4bcd000e098265a6ec63d4b0cf3852fMady Mellor        SliceItem header = SliceQuery.find(slice, FORMAT_SLICE, null, nonHints);
288968346929453133f937381a2e685bc4e47788e2cMady Mellor        if (header != null && isValidHeader(header)) {
289968346929453133f937381a2e685bc4e47788e2cMady Mellor            return header;
2906b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        }
291968346929453133f937381a2e685bc4e47788e2cMady Mellor        return null;
2926b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
2936b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
29453380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    @Nullable
29553380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    private static SliceItem getSeeMoreItem(@NonNull Slice slice) {
29653380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        SliceItem item = SliceQuery.find(slice, null, HINT_SEE_MORE, null);
29753380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        if (item != null && item.hasHint(HINT_SEE_MORE)) {
29853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor            if (FORMAT_SLICE.equals(item.getFormat())) {
29953380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor                List<SliceItem> items = item.getSlice().getItems();
30053380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor                if (items.size() == 1 && FORMAT_ACTION.equals(items.get(0).getFormat())) {
30153380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor                    return items.get(0);
30253380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor                }
30353380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor                return item;
30453380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor            }
30553380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        }
30653380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        return null;
30753380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    }
30853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor
30992952f5bbd2b743091af437767b0b48e48d292b5Mady Mellor    /**
31092952f5bbd2b743091af437767b0b48e48d292b5Mady Mellor     * @return whether the provided slice item is a valid header.
31192952f5bbd2b743091af437767b0b48e48d292b5Mady Mellor     */
31292952f5bbd2b743091af437767b0b48e48d292b5Mady Mellor    public static boolean isValidHeader(SliceItem sliceItem) {
313bb51b5909dd8d5b233cd675fbc6fe74c42f48d3cMady Mellor        if (FORMAT_SLICE.equals(sliceItem.getFormat()) && !sliceItem.hasAnyHints(HINT_LIST_ITEM,
31492952f5bbd2b743091af437767b0b48e48d292b5Mady Mellor                HINT_ACTIONS, HINT_KEYWORDS, HINT_SEE_MORE)) {
315968346929453133f937381a2e685bc4e47788e2cMady Mellor             // Minimum valid header is a slice with text
316968346929453133f937381a2e685bc4e47788e2cMady Mellor            SliceItem item = SliceQuery.find(sliceItem, FORMAT_TEXT, (String) null, null);
317968346929453133f937381a2e685bc4e47788e2cMady Mellor            return item != null;
3186b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        }
319968346929453133f937381a2e685bc4e47788e2cMady Mellor        return false;
3206b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
3216b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor}
322