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
19378ff19cef9998493bc715c58d923150cfd3d816Mady Mellorimport static android.app.slice.Slice.HINT_HORIZONTAL;
20891ce204e1ecd60342507c7bd0c1160bac93be01Mady Mellorimport static android.app.slice.Slice.HINT_PARTIAL;
2153380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellorimport static android.app.slice.Slice.HINT_SEE_MORE;
22af76b3bd62a6b218bb44917b1dddfa1ee4803149Mady Mellorimport static android.app.slice.Slice.HINT_SHORTCUT;
23968346929453133f937381a2e685bc4e47788e2cMady Mellorimport static android.app.slice.Slice.HINT_SUMMARY;
246b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellorimport static android.app.slice.Slice.HINT_TITLE;
254c4a519b7320e1736f55dcd20351d10f692d492cMady Mellorimport static android.app.slice.Slice.SUBTYPE_CONTENT_DESCRIPTION;
263bc2c820c8cbab1cf67dbd836697f780265f0e7aMady Mellorimport static android.app.slice.Slice.SUBTYPE_RANGE;
276b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellorimport static android.app.slice.SliceItem.FORMAT_ACTION;
286b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellorimport static android.app.slice.SliceItem.FORMAT_IMAGE;
29f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikhimport static android.app.slice.SliceItem.FORMAT_INT;
309e9f857ec07b05e1a6885c9fc6a2bf25b813259bJason Monkimport static android.app.slice.SliceItem.FORMAT_LONG;
316b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellorimport static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
326b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellorimport static android.app.slice.SliceItem.FORMAT_SLICE;
336b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellorimport static android.app.slice.SliceItem.FORMAT_TEXT;
3437bd0717b1f1f8851125d60f87b242a57899298cMady Mellor
350707dbe9fa3225cc921a2305a611272f0dee1ca8Mady Mellorimport static androidx.slice.core.SliceHints.HINT_KEYWORDS;
3663fb9955b209f1bb9d19e41df9784bfbdf63defeMady Mellorimport static androidx.slice.core.SliceHints.HINT_LAST_UPDATED;
3763fb9955b209f1bb9d19e41df9784bfbdf63defeMady Mellorimport static androidx.slice.core.SliceHints.HINT_TTL;
386b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
398a2763f580c71e17a0b13e682c73012e902b4232Mady Mellorimport android.content.Context;
408a2763f580c71e17a0b13e682c73012e902b4232Mady Mellorimport android.text.TextUtils;
416b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellorimport android.util.Log;
426b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
434c4a519b7320e1736f55dcd20351d10f692d492cMady Mellorimport androidx.annotation.NonNull;
444c4a519b7320e1736f55dcd20351d10f692d492cMady Mellorimport androidx.annotation.Nullable;
454c4a519b7320e1736f55dcd20351d10f692d492cMady Mellorimport androidx.annotation.RestrictTo;
4685ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikasimport androidx.slice.SliceItem;
47ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellorimport androidx.slice.core.SliceAction;
48ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellorimport androidx.slice.core.SliceActionImpl;
4985ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikasimport androidx.slice.core.SliceQuery;
5085ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikasimport androidx.slice.view.R;
516b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
52d0babfc47d7a429b80c1f7a3998d57c0aa15dd83Jason Monkimport java.util.ArrayList;
53d0babfc47d7a429b80c1f7a3998d57c0aa15dd83Jason Monkimport java.util.List;
54d0babfc47d7a429b80c1f7a3998d57c0aa15dd83Jason Monk
556b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor/**
566b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor * Extracts information required to present content in a row format from a slice.
576b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor * @hide
586b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor */
596b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
606b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellorpublic class RowContent {
616b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    private static final String TAG = "RowContent";
626b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
63af76b3bd62a6b218bb44917b1dddfa1ee4803149Mady Mellor    private SliceItem mPrimaryAction;
6453380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    private SliceItem mRowSlice;
656b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    private SliceItem mStartItem;
666b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    private SliceItem mTitleItem;
676b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    private SliceItem mSubtitleItem;
68968346929453133f937381a2e685bc4e47788e2cMady Mellor    private SliceItem mSummaryItem;
696b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    private ArrayList<SliceItem> mEndItems = new ArrayList<>();
70ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor    private ArrayList<SliceAction> mToggleItems = new ArrayList<>();
71853c11f11cd3d1378eac2c37d1e8c258420644a8Amin Shaikh    private SliceItem mRange;
724c4a519b7320e1736f55dcd20351d10f692d492cMady Mellor    private SliceItem mContentDescr;
734c4a519b7320e1736f55dcd20351d10f692d492cMady Mellor    private boolean mEndItemsContainAction;
74968346929453133f937381a2e685bc4e47788e2cMady Mellor    private boolean mIsHeader;
758a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    private int mLineCount = 0;
768a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    private int mMaxHeight;
778a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    private int mMinHeight;
788dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor    private int mRangeHeight;
796b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
808a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    public RowContent(Context context, SliceItem rowSlice, boolean isHeader) {
81968346929453133f937381a2e685bc4e47788e2cMady Mellor        populate(rowSlice, isHeader);
828a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor        mMaxHeight = context.getResources().getDimensionPixelSize(R.dimen.abc_slice_row_max_height);
838a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor        mMinHeight = context.getResources().getDimensionPixelSize(R.dimen.abc_slice_row_min_height);
848dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor        mRangeHeight = context.getResources().getDimensionPixelSize(
858dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor                R.dimen.abc_slice_row_range_height);
866b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
876b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
886b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    /**
896b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor     * @return whether this row has content that is valid to display.
906b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor     */
918a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    private boolean populate(SliceItem rowSlice, boolean isHeader) {
92968346929453133f937381a2e685bc4e47788e2cMady Mellor        mIsHeader = isHeader;
9353380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        mRowSlice = rowSlice;
946b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        if (!isValidRow(rowSlice)) {
956b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor            Log.w(TAG, "Provided SliceItem is invalid for RowContent");
966b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor            return false;
976b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        }
98977517c547084945539210fd3bf075bb81077105Mady Mellor        determineStartAndPrimaryAction(rowSlice);
99d0babfc47d7a429b80c1f7a3998d57c0aa15dd83Jason Monk
1004c4a519b7320e1736f55dcd20351d10f692d492cMady Mellor        mContentDescr = SliceQuery.findSubtype(rowSlice, FORMAT_TEXT, SUBTYPE_CONTENT_DESCRIPTION);
1014c4a519b7320e1736f55dcd20351d10f692d492cMady Mellor
1026b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        // Filter anything not viable for displaying in a row
103f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh        ArrayList<SliceItem> rowItems = filterInvalidItems(rowSlice);
1046b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        // If we've only got one item that's a slice / action use those items instead
1056b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        if (rowItems.size() == 1 && (FORMAT_ACTION.equals(rowItems.get(0).getFormat())
106af76b3bd62a6b218bb44917b1dddfa1ee4803149Mady Mellor                || FORMAT_SLICE.equals(rowItems.get(0).getFormat()))
107977517c547084945539210fd3bf075bb81077105Mady Mellor                && !rowItems.get(0).hasAnyHints(HINT_SHORTCUT, HINT_TITLE)) {
1086b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor            if (isValidRow(rowItems.get(0))) {
1096b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor                rowSlice = rowItems.get(0);
110f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh                rowItems = filterInvalidItems(rowSlice);
1116b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor            }
1126b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        }
113853c11f11cd3d1378eac2c37d1e8c258420644a8Amin Shaikh        if (SUBTYPE_RANGE.equals(rowSlice.getSubType())) {
114853c11f11cd3d1378eac2c37d1e8c258420644a8Amin Shaikh            mRange = rowSlice;
115f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh        }
1166b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        if (rowItems.size() > 0) {
117977517c547084945539210fd3bf075bb81077105Mady Mellor            // Remove the things we already know about
118977517c547084945539210fd3bf075bb81077105Mady Mellor            if (mStartItem != null) {
119977517c547084945539210fd3bf075bb81077105Mady Mellor                rowItems.remove(mStartItem);
120977517c547084945539210fd3bf075bb81077105Mady Mellor            }
121977517c547084945539210fd3bf075bb81077105Mady Mellor            if (mPrimaryAction != null) {
122977517c547084945539210fd3bf075bb81077105Mady Mellor                rowItems.remove(mPrimaryAction);
1236b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor            }
124af76b3bd62a6b218bb44917b1dddfa1ee4803149Mady Mellor
1256b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor            // Text + end items
126238b9b6aad4ef0c63acbecfa89605a3d753931feMady Mellor            ArrayList<SliceItem> endItems = new ArrayList<>();
1276b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor            for (int i = 0; i < rowItems.size(); i++) {
1286b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor                final SliceItem item = rowItems.get(i);
1296b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor                if (FORMAT_TEXT.equals(item.getFormat())) {
1306b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor                    if ((mTitleItem == null || !mTitleItem.hasHint(HINT_TITLE))
131968346929453133f937381a2e685bc4e47788e2cMady Mellor                            && item.hasHint(HINT_TITLE) && !item.hasHint(HINT_SUMMARY)) {
1326b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor                        mTitleItem = item;
133968346929453133f937381a2e685bc4e47788e2cMady Mellor                    } else if (mSubtitleItem == null && !item.hasHint(HINT_SUMMARY)) {
1346b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor                        mSubtitleItem = item;
135968346929453133f937381a2e685bc4e47788e2cMady Mellor                    } else if (mSummaryItem == null && item.hasHint(HINT_SUMMARY)) {
136968346929453133f937381a2e685bc4e47788e2cMady Mellor                        mSummaryItem = item;
1376b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor                    }
1386b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor                } else {
139238b9b6aad4ef0c63acbecfa89605a3d753931feMady Mellor                    endItems.add(item);
140238b9b6aad4ef0c63acbecfa89605a3d753931feMady Mellor                }
141238b9b6aad4ef0c63acbecfa89605a3d753931feMady Mellor            }
1428a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor            if (hasText(mTitleItem)) {
1438a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor                mLineCount++;
1448a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor            }
1458a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor            if (hasText(mSubtitleItem)) {
1468a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor                mLineCount++;
1478a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor            }
14807a4a56611cc044fd48b052db05aea332201216eJason Monk            // Special rules for end items: only one timestamp
149238b9b6aad4ef0c63acbecfa89605a3d753931feMady Mellor            boolean hasTimestamp = mStartItem != null
1509e9f857ec07b05e1a6885c9fc6a2bf25b813259bJason Monk                    && FORMAT_LONG.equals(mStartItem.getFormat());
151238b9b6aad4ef0c63acbecfa89605a3d753931feMady Mellor            for (int i = 0; i < endItems.size(); i++) {
152238b9b6aad4ef0c63acbecfa89605a3d753931feMady Mellor                final SliceItem item = endItems.get(i);
15307a4a56611cc044fd48b052db05aea332201216eJason Monk                boolean isAction = SliceQuery.find(item, FORMAT_ACTION) != null;
1549e9f857ec07b05e1a6885c9fc6a2bf25b813259bJason Monk                if (FORMAT_LONG.equals(item.getFormat())) {
155238b9b6aad4ef0c63acbecfa89605a3d753931feMady Mellor                    if (!hasTimestamp) {
156238b9b6aad4ef0c63acbecfa89605a3d753931feMady Mellor                        hasTimestamp = true;
157238b9b6aad4ef0c63acbecfa89605a3d753931feMady Mellor                        mEndItems.add(item);
158238b9b6aad4ef0c63acbecfa89605a3d753931feMady Mellor                    }
15907a4a56611cc044fd48b052db05aea332201216eJason Monk                } else {
160ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                    processContent(item, isAction);
1616b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor                }
1626b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor            }
1636b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        }
1646b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        return isValid();
1656b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
1666b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
167ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor    private void processContent(@NonNull SliceItem item, boolean isAction) {
168ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor        if (isAction) {
169ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor            SliceAction ac = new SliceActionImpl(item);
170ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor            if (ac.isToggle()) {
171ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor                mToggleItems.add(ac);
172ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor            }
173ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor        }
174ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor        mEndItems.add(item);
175ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor        mEndItemsContainAction |= isAction;
176ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor    }
177ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor
1786b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    /**
179977517c547084945539210fd3bf075bb81077105Mady Mellor     * Sets the {@link #getPrimaryAction()} and {@link #getStartItem()} for this row.
180977517c547084945539210fd3bf075bb81077105Mady Mellor     */
181977517c547084945539210fd3bf075bb81077105Mady Mellor    private void determineStartAndPrimaryAction(@NonNull SliceItem rowSlice) {
182977517c547084945539210fd3bf075bb81077105Mady Mellor        List<SliceItem> possibleStartItems = SliceQuery.findAll(rowSlice, null, HINT_TITLE, null);
183977517c547084945539210fd3bf075bb81077105Mady Mellor        if (possibleStartItems.size() > 0) {
184977517c547084945539210fd3bf075bb81077105Mady Mellor            // The start item will be at position 0 if it exists
185977517c547084945539210fd3bf075bb81077105Mady Mellor            String format = possibleStartItems.get(0).getFormat();
186977517c547084945539210fd3bf075bb81077105Mady Mellor            if ((FORMAT_ACTION.equals(format)
187977517c547084945539210fd3bf075bb81077105Mady Mellor                    && SliceQuery.find(possibleStartItems.get(0), FORMAT_IMAGE) != null)
188977517c547084945539210fd3bf075bb81077105Mady Mellor                    || FORMAT_SLICE.equals(format)
1894e324256a5aadb8e1001b0ee7ead3cda48bfec7fAlan Viverette                    || FORMAT_LONG.equals(format)
190977517c547084945539210fd3bf075bb81077105Mady Mellor                    || FORMAT_IMAGE.equals(format)) {
191977517c547084945539210fd3bf075bb81077105Mady Mellor                mStartItem = possibleStartItems.get(0);
192977517c547084945539210fd3bf075bb81077105Mady Mellor            }
193977517c547084945539210fd3bf075bb81077105Mady Mellor        }
194977517c547084945539210fd3bf075bb81077105Mady Mellor
195977517c547084945539210fd3bf075bb81077105Mady Mellor        String[] hints = new String[] {HINT_SHORTCUT, HINT_TITLE};
196977517c547084945539210fd3bf075bb81077105Mady Mellor        List<SliceItem> possiblePrimaries = SliceQuery.findAll(rowSlice, FORMAT_SLICE, hints, null);
197977517c547084945539210fd3bf075bb81077105Mady Mellor        if (possiblePrimaries.isEmpty() && FORMAT_ACTION.equals(rowSlice.getFormat())
198977517c547084945539210fd3bf075bb81077105Mady Mellor                && rowSlice.getSlice().getItems().size() == 1) {
199977517c547084945539210fd3bf075bb81077105Mady Mellor            mPrimaryAction = rowSlice;
200977517c547084945539210fd3bf075bb81077105Mady Mellor        } else if (mStartItem != null && possiblePrimaries.size() > 1
201977517c547084945539210fd3bf075bb81077105Mady Mellor                && possiblePrimaries.get(0) == mStartItem) {
202977517c547084945539210fd3bf075bb81077105Mady Mellor            // Next item is the primary action
203977517c547084945539210fd3bf075bb81077105Mady Mellor            mPrimaryAction = possiblePrimaries.get(1);
204977517c547084945539210fd3bf075bb81077105Mady Mellor        } else if (possiblePrimaries.size() > 0) {
205977517c547084945539210fd3bf075bb81077105Mady Mellor            mPrimaryAction = possiblePrimaries.get(0);
206977517c547084945539210fd3bf075bb81077105Mady Mellor        }
207977517c547084945539210fd3bf075bb81077105Mady Mellor    }
208977517c547084945539210fd3bf075bb81077105Mady Mellor
209977517c547084945539210fd3bf075bb81077105Mady Mellor    /**
21053380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     * @return the {@link SliceItem} used to populate this row.
21153380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     */
21253380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    @NonNull
21353380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    public SliceItem getSlice() {
21453380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        return mRowSlice;
21553380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    }
21653380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor
21753380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    /**
218853c11f11cd3d1378eac2c37d1e8c258420644a8Amin Shaikh     * @return the {@link SliceItem} representing the range in the row; can be null.
219f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh     */
220f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh    @Nullable
221853c11f11cd3d1378eac2c37d1e8c258420644a8Amin Shaikh    public SliceItem getRange() {
222853c11f11cd3d1378eac2c37d1e8c258420644a8Amin Shaikh        return mRange;
223f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh    }
224f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh
225f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh    /**
226c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor     * @return the {@link SliceItem} for the icon to use for the input range thumb drawable.
227c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor     */
228c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor    @Nullable
229c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor    public SliceItem getInputRangeThumb() {
230c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor        if (mRange != null) {
231c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor            List<SliceItem> items = mRange.getSlice().getItems();
232c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor            for (int i = 0; i < items.size(); i++) {
233c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor                if (FORMAT_IMAGE.equals(items.get(i).getFormat())) {
234c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor                    return items.get(i);
235c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor                }
236c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor            }
237c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor        }
238c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor        return null;
239c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor    }
240c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor
241c1a0996f6ada4bcac69f7aa07048fdd2c9bba4d7Mady Mellor    /**
24253380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     * @return the {@link SliceItem} used for the main intent for this row; can be null.
2436b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor     */
2446b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    @Nullable
245af76b3bd62a6b218bb44917b1dddfa1ee4803149Mady Mellor    public SliceItem getPrimaryAction() {
246af76b3bd62a6b218bb44917b1dddfa1ee4803149Mady Mellor        return mPrimaryAction;
2476b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
2486b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
24953380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    /**
25053380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     * @return the {@link SliceItem} to display at the start of this row; can be null.
25153380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     */
2526b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    @Nullable
2536b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    public SliceItem getStartItem() {
254968346929453133f937381a2e685bc4e47788e2cMady Mellor        return mIsHeader ? null : mStartItem;
2556b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
2566b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
25753380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    /**
25853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     * @return the {@link SliceItem} representing the title text for this row; can be null.
25953380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     */
2606b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    @Nullable
2616b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    public SliceItem getTitleItem() {
2626b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        return mTitleItem;
2636b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
2646b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
26553380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    /**
26653380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     * @return the {@link SliceItem} representing the subtitle text for this row; can be null.
26753380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     */
2686b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    @Nullable
2696b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    public SliceItem getSubtitleItem() {
2706b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        return mSubtitleItem;
2716b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
2726b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
273968346929453133f937381a2e685bc4e47788e2cMady Mellor    @Nullable
274968346929453133f937381a2e685bc4e47788e2cMady Mellor    public SliceItem getSummaryItem() {
275968346929453133f937381a2e685bc4e47788e2cMady Mellor        return mSummaryItem == null ? mSubtitleItem : mSummaryItem;
276968346929453133f937381a2e685bc4e47788e2cMady Mellor    }
277968346929453133f937381a2e685bc4e47788e2cMady Mellor
27853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    /**
27953380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     * @return the list of {@link SliceItem} that can be shown as items at the end of the row.
28053380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     */
2816b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    public ArrayList<SliceItem> getEndItems() {
2826b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        return mEndItems;
2836b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
2846b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
2856b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    /**
286ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor     * @return a list of toggles associated with this row.
287ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor     */
288ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor    public ArrayList<SliceAction> getToggleItems() {
289ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor        return mToggleItems;
290ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor    }
291ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor
292ca12087a732c2e40be512a8d9d25e0aec8bf92d8Mady Mellor    /**
2934c4a519b7320e1736f55dcd20351d10f692d492cMady Mellor     * @return the content description to use for this row.
2944c4a519b7320e1736f55dcd20351d10f692d492cMady Mellor     */
2954c4a519b7320e1736f55dcd20351d10f692d492cMady Mellor    @Nullable
2964c4a519b7320e1736f55dcd20351d10f692d492cMady Mellor    public CharSequence getContentDescription() {
2974c4a519b7320e1736f55dcd20351d10f692d492cMady Mellor        return mContentDescr != null ? mContentDescr.getText() : null;
2984c4a519b7320e1736f55dcd20351d10f692d492cMady Mellor    }
2994c4a519b7320e1736f55dcd20351d10f692d492cMady Mellor
3004c4a519b7320e1736f55dcd20351d10f692d492cMady Mellor    /**
301af76b3bd62a6b218bb44917b1dddfa1ee4803149Mady Mellor     * @return whether {@link #getEndItems()} contains a SliceItem with FORMAT_SLICE, HINT_SHORTCUT
302bfeddbaf2e0d5707b101a91fa1287c93757ff4a9Amin Shaikh     */
303bfeddbaf2e0d5707b101a91fa1287c93757ff4a9Amin Shaikh    public boolean endItemsContainAction() {
304bfeddbaf2e0d5707b101a91fa1287c93757ff4a9Amin Shaikh        return mEndItemsContainAction;
305bfeddbaf2e0d5707b101a91fa1287c93757ff4a9Amin Shaikh    }
306bfeddbaf2e0d5707b101a91fa1287c93757ff4a9Amin Shaikh
307bfeddbaf2e0d5707b101a91fa1287c93757ff4a9Amin Shaikh    /**
3088a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor     * @return the number of lines of text contained in this row.
3098a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor     */
3108a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    public int getLineCount() {
3118a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor        return mLineCount;
3128a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    }
3138a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor
3148a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    /**
3158a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor     * @return the height to display a row at when it is used as a small template.
3168a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor     */
3178a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    public int getSmallHeight() {
3188dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor        return getRange() != null
3198dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor                ? getActualHeight()
320ec2359f11170a2742cd1650900de320aa22eab58Mady Mellor                : mMaxHeight;
3218a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    }
3228a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor
3238a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    /**
3248a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor     * @return the height the content in this template requires to be displayed.
3258a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor     */
3268a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    public int getActualHeight() {
327ec2359f11170a2742cd1650900de320aa22eab58Mady Mellor        if (!isValid()) {
328ec2359f11170a2742cd1650900de320aa22eab58Mady Mellor            return 0;
329ec2359f11170a2742cd1650900de320aa22eab58Mady Mellor        }
3308dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor        int rowHeight = (getLineCount() > 1 || mIsHeader) ? mMaxHeight : mMinHeight;
3318dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor        if (getRange() != null) {
3328dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor            if (getLineCount() > 0) {
3338dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor                rowHeight += mRangeHeight;
3348dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor            } else {
3358dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor                rowHeight = mIsHeader ? mMaxHeight : mRangeHeight;
3368dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor            }
337ec2359f11170a2742cd1650900de320aa22eab58Mady Mellor        }
3388dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor        return rowHeight;
3398a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    }
3408a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor
3418a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    private static boolean hasText(SliceItem textSlice) {
342891ce204e1ecd60342507c7bd0c1160bac93be01Mady Mellor        return textSlice != null
343891ce204e1ecd60342507c7bd0c1160bac93be01Mady Mellor                && (textSlice.hasHint(HINT_PARTIAL)
344891ce204e1ecd60342507c7bd0c1160bac93be01Mady Mellor                    || !TextUtils.isEmpty(textSlice.getText()));
3458a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    }
3468a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor
3478a2763f580c71e17a0b13e682c73012e902b4232Mady Mellor    /**
34853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     * @return whether this row content represents a default see more item.
34953380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     */
35053380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    public boolean isDefaultSeeMore() {
35153380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        return FORMAT_ACTION.equals(mRowSlice.getFormat())
35253380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor                && mRowSlice.getSlice().hasHint(HINT_SEE_MORE)
35353380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor                && mRowSlice.getSlice().getItems().isEmpty();
35453380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    }
35553380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor
35653380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    /**
35753380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     * @return whether this row has content that is valid to display.
35853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     */
35953380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    public boolean isValid() {
36053380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor        return mStartItem != null
361977517c547084945539210fd3bf075bb81077105Mady Mellor                || mPrimaryAction != null
36253380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor                || mTitleItem != null
36353380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor                || mSubtitleItem != null
36453380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor                || mEndItems.size() > 0
3658dc56e6039af468e05c213ef6562c9c6624aaf8aMady Mellor                || mRange != null
36653380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor                || isDefaultSeeMore();
36753380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    }
36853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor
36953380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    /**
3706b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor     * @return whether this is a valid item to use to populate a row of content.
3716b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor     */
372f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh    private static boolean isValidRow(SliceItem rowSlice) {
373968346929453133f937381a2e685bc4e47788e2cMady Mellor        if (rowSlice == null) {
374968346929453133f937381a2e685bc4e47788e2cMady Mellor            return false;
375968346929453133f937381a2e685bc4e47788e2cMady Mellor        }
3766b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        // Must be slice or action
377f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh        if (FORMAT_SLICE.equals(rowSlice.getFormat())
378f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh                || FORMAT_ACTION.equals(rowSlice.getFormat())) {
379f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh            List<SliceItem> rowItems = rowSlice.getSlice().getItems();
380977517c547084945539210fd3bf075bb81077105Mady Mellor            // Special case: default see more just has an action but no other items
381977517c547084945539210fd3bf075bb81077105Mady Mellor            if (rowSlice.hasHint(HINT_SEE_MORE) && rowItems.isEmpty()) {
382977517c547084945539210fd3bf075bb81077105Mady Mellor                return true;
383977517c547084945539210fd3bf075bb81077105Mady Mellor            }
384977517c547084945539210fd3bf075bb81077105Mady Mellor            // Must have at least one legitimate child
3856b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor            for (int i = 0; i < rowItems.size(); i++) {
386f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh                if (isValidRowContent(rowSlice, rowItems.get(i))) {
3876b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor                    return true;
3886b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor                }
3896b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor            }
3906b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        }
3916b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        return false;
3926b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
3936b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
39453380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor    /**
39553380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     * @return list of {@link SliceItem}s that are valid to display in a row according
39653380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     * to {@link #isValidRowContent(SliceItem, SliceItem)}.
39753380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor     */
398f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh    private static ArrayList<SliceItem> filterInvalidItems(SliceItem rowSlice) {
3996b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        ArrayList<SliceItem> filteredList = new ArrayList<>();
400f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh        for (SliceItem i : rowSlice.getSlice().getItems()) {
401f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh            if (isValidRowContent(rowSlice, i)) {
4026b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor                filteredList.add(i);
4036b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor            }
4046b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        }
4056b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        return filteredList;
4066b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
4076b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor
4086b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    /**
409977517c547084945539210fd3bf075bb81077105Mady Mellor     * @return whether this item is valid content to visibly appear in a row.
4106b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor     */
411f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh    private static boolean isValidRowContent(SliceItem slice, SliceItem item) {
412378ff19cef9998493bc715c58d923150cfd3d816Mady Mellor        if (item.hasAnyHints(HINT_KEYWORDS, HINT_TTL, HINT_LAST_UPDATED, HINT_HORIZONTAL)
413977517c547084945539210fd3bf075bb81077105Mady Mellor                || SUBTYPE_CONTENT_DESCRIPTION.equals(item.getSubType())) {
414bb51b5909dd8d5b233cd675fbc6fe74c42f48d3cMady Mellor            return false;
415bb51b5909dd8d5b233cd675fbc6fe74c42f48d3cMady Mellor        }
4166b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor        final String itemFormat = item.getFormat();
417977517c547084945539210fd3bf075bb81077105Mady Mellor        return FORMAT_IMAGE.equals(itemFormat)
418977517c547084945539210fd3bf075bb81077105Mady Mellor                || FORMAT_TEXT.equals(itemFormat)
4199e9f857ec07b05e1a6885c9fc6a2bf25b813259bJason Monk                || FORMAT_LONG.equals(itemFormat)
420f2cdc3aa79e0798d6987985ab94395914b83b7e4Amin Shaikh                || FORMAT_ACTION.equals(itemFormat)
421977517c547084945539210fd3bf075bb81077105Mady Mellor                || FORMAT_REMOTE_INPUT.equals(itemFormat)
422977517c547084945539210fd3bf075bb81077105Mady Mellor                || FORMAT_SLICE.equals(itemFormat)
423853c11f11cd3d1378eac2c37d1e8c258420644a8Amin Shaikh                || (FORMAT_INT.equals(itemFormat) && SUBTYPE_RANGE.equals(slice.getSubType()));
4246b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor    }
4256b5cd6162737bc3a885d58c22549e5b17beded1aMady Mellor}
426