blob: accfa49095d231c4d8c102a1b9181d709a43e6cd [file] [log] [blame]
/*
* Copyright 2017 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.
*/
package androidx.app.slice.widget;
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_REMOTE_INPUT;
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 android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import androidx.app.slice.SliceItem;
import androidx.app.slice.core.SliceHints;
import androidx.app.slice.core.SliceQuery;
/**
* Extracts information required to present content in a row format from a slice.
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class RowContent {
private static final String TAG = "RowContent";
private SliceItem mContentIntent;
private SliceItem mStartItem;
private SliceItem mTitleItem;
private SliceItem mSubtitleItem;
private SliceItem mToggleItem;
private ArrayList<SliceItem> mEndItems = new ArrayList<>();
public RowContent(SliceItem rowSlice, boolean showStartItem) {
populate(rowSlice, showStartItem);
}
/**
* Resets the content.
*/
public void reset() {
mContentIntent = null;
mStartItem = null;
mTitleItem = null;
mSubtitleItem = null;
mToggleItem = null;
mEndItems.clear();
}
/**
* @return whether this row has content that is valid to display.
*/
public boolean populate(SliceItem rowSlice, boolean showStartItem) {
reset();
if (!isValidRow(rowSlice)) {
Log.w(TAG, "Provided SliceItem is invalid for RowContent");
return false;
}
// Filter anything not viable for displaying in a row
ArrayList<SliceItem> rowItems = filterInvalidItems(rowSlice.getSlice().getItems());
// If we've only got one item that's a slice / action use those items instead
if (rowItems.size() == 1 && (FORMAT_ACTION.equals(rowItems.get(0).getFormat())
|| FORMAT_SLICE.equals(rowItems.get(0).getFormat()))) {
if (isValidRow(rowItems.get(0))) {
rowSlice = rowItems.get(0);
rowItems = filterInvalidItems(rowSlice.getSlice().getItems());
}
}
// Content intent
if (FORMAT_ACTION.equals(rowSlice.getFormat())) {
mContentIntent = rowSlice;
}
if (rowItems.size() > 0) {
// Start item
if (showStartItem && isStartType(rowItems.get(0))) {
mStartItem = rowItems.get(0);
rowItems.remove(mStartItem);
}
// Text + end items
for (int i = 0; i < rowItems.size(); i++) {
final SliceItem item = rowItems.get(i);
if (FORMAT_TEXT.equals(item.getFormat())) {
if ((mTitleItem == null || !mTitleItem.hasHint(HINT_TITLE))
&& item.hasHint(HINT_TITLE)) {
mTitleItem = item;
} else if (mSubtitleItem == null) {
mSubtitleItem = item;
}
} else {
mEndItems.add(item);
}
}
}
checkForToggle();
return isValid();
}
private void checkForToggle() {
// Check if we have a content intent that is for a toggle
if (mContentIntent != null && SliceQuery.hasHints(mContentIntent.getSlice(),
SliceHints.SUBTYPE_TOGGLE)) {
mToggleItem = mContentIntent;
return;
}
// Check if there's a toggle in our end items
ArrayList<SliceItem> endItems = getEndItems();
for (int i = 0; i < endItems.size(); i++) {
final SliceItem endItem = endItems.get(i);
if (FORMAT_ACTION.equals(endItem.getFormat())
&& (endItem.hasHint(SliceHints.SUBTYPE_TOGGLE)
|| SliceQuery.hasHints(endItem.getSlice(), SliceHints.SUBTYPE_TOGGLE))) {
mToggleItem = endItem;
return;
}
}
}
/**
* @return whether this row has content that is valid to display.
*/
public boolean isValid() {
return mStartItem != null
|| mTitleItem != null
|| mSubtitleItem != null
|| mEndItems.size() > 0;
}
@Nullable
public SliceItem getContentIntent() {
return mContentIntent;
}
@Nullable
public SliceItem getStartItem() {
return mStartItem;
}
@Nullable
public SliceItem getTitleItem() {
return mTitleItem;
}
@Nullable
public SliceItem getSubtitleItem() {
return mSubtitleItem;
}
@Nullable
public SliceItem getToggleItem() {
return mToggleItem;
}
public ArrayList<SliceItem> getEndItems() {
return mEndItems;
}
/**
* @return whether this is a valid item to use to populate a row of content.
*/
private static boolean isValidRow(SliceItem item) {
// Must be slice or action
if (FORMAT_SLICE.equals(item.getFormat()) || FORMAT_ACTION.equals(item.getFormat())) {
// Must have at least one legitimate child
List<SliceItem> rowItems = item.getSlice().getItems();
for (int i = 0; i < rowItems.size(); i++) {
if (isValidRowContent(rowItems.get(i))) {
return true;
}
}
}
Log.w(TAG, "invalid row content because not a slice or action");
return false;
}
private static ArrayList<SliceItem> filterInvalidItems(List<SliceItem> items) {
ArrayList<SliceItem> filteredList = new ArrayList<>();
for (SliceItem i : items) {
if (isValidRowContent(i)) {
filteredList.add(i);
}
}
return filteredList;
}
/**
* @return whether this item has valid content to display in a row.
*/
private static boolean isValidRowContent(SliceItem item) {
// TODO -- filter for shortcut once that's in
final String itemFormat = item.getFormat();
// Must be a format that is presentable
return FORMAT_TEXT.equals(itemFormat)
|| FORMAT_IMAGE.equals(itemFormat)
|| FORMAT_TIMESTAMP.equals(itemFormat)
|| FORMAT_REMOTE_INPUT.equals(itemFormat)
|| FORMAT_ACTION.equals(itemFormat);
}
/**
* @return Whether this item is appropriate to be considered a "start" item, i.e. go in the
* front slot of a row.
*/
private static boolean isStartType(SliceItem item) {
final String type = item.getFormat();
return (!item.hasHint(SliceHints.SUBTYPE_TOGGLE)
&& item.hasHint(HINT_TITLE)
&& (FORMAT_ACTION.equals(type) && (SliceQuery.find(item, FORMAT_IMAGE) != null)))
|| FORMAT_IMAGE.equals(type)
|| FORMAT_TIMESTAMP.equals(type);
}
}