blob: 86e9409b753c93f38046efc386f076663a16b8a0 [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_ACTIONS;
import static android.app.slice.Slice.HINT_LIST;
import static android.app.slice.Slice.HINT_LIST_ITEM;
import static android.app.slice.Slice.SUBTYPE_COLOR;
import static android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_INT;
import static android.app.slice.SliceItem.FORMAT_SLICE;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import java.util.ArrayList;
import java.util.List;
import androidx.app.slice.Slice;
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 list format from a slice.
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class ListContent {
private SliceItem mColorItem;
private SliceItem mSummaryItem;
private ArrayList<SliceItem> mRowItems = new ArrayList<>();
private boolean mHasHeader;
public ListContent(Slice slice) {
populate(slice);
}
/**
* Resets the content.
*/
public void reset() {
mColorItem = null;
mSummaryItem = null;
mRowItems.clear();
mHasHeader = false;
}
/**
* @return whether this row has content that is valid to display.
*/
public boolean populate(Slice slice) {
reset();
mColorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
// Find summary
SliceItem summaryItem = getSummaryItem(slice);
mSummaryItem = summaryItem;
// Filter + create row items
List<SliceItem> children = slice.getItems();
for (int i = 0; i < children.size(); i++) {
final SliceItem child = children.get(i);
final String format = child.getFormat();
if (!child.hasAnyHints(SliceHints.HINT_SUMMARY, HINT_ACTIONS)
&& (FORMAT_ACTION.equals(format) || FORMAT_SLICE.equals(format))) {
if (!mHasHeader && !child.hasHint(HINT_LIST_ITEM)) {
mHasHeader = true;
mRowItems.add(0, child);
} else {
mRowItems.add(child);
}
}
}
return isValid();
}
/**
* @return whether this list has content that is valid to display.
*/
public boolean isValid() {
return mSummaryItem != null
|| mRowItems.size() > 0;
}
@Nullable
public SliceItem getColorItem() {
return mColorItem;
}
@Nullable
public SliceItem getSummaryItem() {
return mSummaryItem;
}
public ArrayList<SliceItem> getRowItems() {
return mRowItems;
}
/**
* @return whether this list has a header or not.
*/
public boolean hasHeader() {
return mHasHeader;
}
/**
* @return A slice item of format slice that is hinted to be shown when the slice is in small
* format, or is the best option if nothing is appropriately hinted.
*/
private static SliceItem getSummaryItem(@NonNull Slice slice) {
List<SliceItem> items = slice.getItems();
// See if a summary is specified
SliceItem summary = SliceQuery.find(slice, FORMAT_SLICE, SliceHints.HINT_SUMMARY, null);
if (summary != null) {
return summary;
}
// Otherwise use the first non-color item and use it if it's a slice
SliceItem firstSlice = null;
for (int i = 0; i < items.size(); i++) {
if (!FORMAT_INT.equals(items.get(i).getFormat())) {
firstSlice = items.get(i);
break;
}
}
if (firstSlice != null && FORMAT_SLICE.equals(firstSlice.getFormat())) {
// Check if this slice is appropriate to use to populate small template
if (firstSlice.hasHint(HINT_LIST)) {
// Check for header, use that if it exists
SliceItem listHeader = SliceQuery.find(firstSlice, FORMAT_SLICE,
null,
new String[] {
HINT_LIST_ITEM, HINT_LIST
});
if (listHeader != null) {
return findFirstSlice(listHeader);
} else {
// Otherwise use the first list item
SliceItem newFirst = firstSlice.getSlice().getItems().get(0);
return findFirstSlice(newFirst);
}
} else {
// Not a list, find first slice with non-slice children
return findFirstSlice(firstSlice);
}
}
// Fallback, just use this and convert to SliceItem type slice
Slice.Builder sb = new Slice.Builder(slice.getUri());
Slice s = sb.addSubSlice(slice).build();
return s.getItems().get(0);
}
/**
* @return Finds the first slice that has non-slice children.
*/
private static SliceItem findFirstSlice(SliceItem slice) {
if (!FORMAT_SLICE.equals(slice.getFormat())) {
return slice;
}
List<SliceItem> items = slice.getSlice().getItems();
for (int i = 0; i < items.size(); i++) {
if (FORMAT_SLICE.equals(items.get(i).getFormat())) {
SliceItem childSlice = items.get(i);
return findFirstSlice(childSlice);
} else {
// Doesn't have slice children so return it
return slice;
}
}
// Slices all the way down, just return it
return slice;
}
}