| /* |
| * 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.slice.core; |
| |
| import static android.app.slice.SliceItem.FORMAT_ACTION; |
| import static android.app.slice.SliceItem.FORMAT_SLICE; |
| |
| import android.net.Uri; |
| import android.text.TextUtils; |
| |
| import androidx.annotation.RequiresApi; |
| import androidx.annotation.RestrictTo; |
| import androidx.slice.Slice; |
| import androidx.slice.SliceItem; |
| |
| import java.util.ArrayDeque; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Deque; |
| import java.util.List; |
| |
| /** |
| * Utilities for finding content within a Slice. |
| * @hide |
| */ |
| @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) |
| @RequiresApi(19) |
| public class SliceQuery { |
| |
| /** |
| */ |
| public static boolean hasAnyHints(SliceItem item, String... hints) { |
| if (hints == null) return false; |
| for (String hint : hints) { |
| if (item.hasHint(hint)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| */ |
| public static boolean hasHints(SliceItem item, String... hints) { |
| if (hints == null) return true; |
| for (String hint : hints) { |
| if (!TextUtils.isEmpty(hint) && !item.hasHint(hint)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| */ |
| public static boolean hasHints(Slice item, String... hints) { |
| if (hints == null) return true; |
| for (String hint : hints) { |
| if (!TextUtils.isEmpty(hint) && !item.hasHint(hint)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| */ |
| public static SliceItem findNotContaining(SliceItem container, List<SliceItem> list) { |
| SliceItem ret = null; |
| while (ret == null && list.size() != 0) { |
| SliceItem remove = list.remove(0); |
| if (!contains(container, remove)) { |
| ret = remove; |
| } |
| } |
| return ret; |
| } |
| |
| /** |
| */ |
| private static boolean contains(SliceItem container, final SliceItem item) { |
| if (container == null || item == null) return false; |
| return findSliceItem(toQueue(container), new Filter<SliceItem>() { |
| @Override |
| public boolean filter(SliceItem s) { |
| return s == item; |
| } |
| }) != null; |
| } |
| |
| /** |
| */ |
| public static List<SliceItem> findAll(SliceItem s, String format) { |
| return findAll(s, format, (String[]) null, null); |
| } |
| |
| /** |
| */ |
| public static List<SliceItem> findAll(Slice s, String format, String hints, String nonHints) { |
| return findAll(s, format, new String[]{ hints }, new String[]{ nonHints }); |
| } |
| |
| /** |
| */ |
| public static List<SliceItem> findAll(SliceItem s, String format, String hints, |
| String nonHints) { |
| return findAll(s, format, new String[]{ hints }, new String[]{ nonHints }); |
| } |
| |
| /** |
| */ |
| public static List<SliceItem> findAll(Slice s, final String format, final String[] hints, |
| final String[] nonHints) { |
| ArrayList<SliceItem> ret = new ArrayList<>(); |
| findAll(toQueue(s), new Filter<SliceItem>() { |
| @Override |
| public boolean filter(SliceItem item) { |
| return checkFormat(item, format) |
| && (hasHints(item, hints) && !hasAnyHints(item, nonHints)); |
| } |
| }, ret); |
| return ret; |
| } |
| |
| /** |
| */ |
| public static List<SliceItem> findAll(SliceItem s, final String format, final String[] hints, |
| final String[] nonHints) { |
| ArrayList<SliceItem> ret = new ArrayList<>(); |
| findAll(toQueue(s), new Filter<SliceItem>() { |
| @Override |
| public boolean filter(SliceItem item) { |
| return checkFormat(item, format) |
| && (hasHints(item, hints) && !hasAnyHints(item, nonHints)); |
| } |
| }, ret); |
| return ret; |
| } |
| |
| /** |
| */ |
| public static SliceItem find(Slice s, String format, String hints, String nonHints) { |
| return find(s, format, new String[]{ hints }, new String[]{ nonHints }); |
| } |
| |
| /** |
| */ |
| public static SliceItem find(Slice s, String format) { |
| return find(s, format, (String[]) null, null); |
| } |
| |
| /** |
| */ |
| public static SliceItem find(SliceItem s, String format) { |
| return find(s, format, (String[]) null, null); |
| } |
| |
| /** |
| */ |
| public static SliceItem find(SliceItem s, String format, String hints, String nonHints) { |
| return find(s, format, new String[]{ hints }, new String[]{ nonHints }); |
| } |
| |
| /** |
| */ |
| public static SliceItem find(Slice s, final String format, final String[] hints, |
| final String[] nonHints) { |
| if (s == null) return null; |
| return findSliceItem(toQueue(s), new Filter<SliceItem>() { |
| @Override |
| public boolean filter(SliceItem item) { |
| return checkFormat(item, format) |
| && (hasHints(item, hints) && !hasAnyHints(item, nonHints)); |
| } |
| }); |
| } |
| |
| /** |
| */ |
| public static SliceItem findSubtype(Slice s, final String format, final String subtype) { |
| if (s == null) return null; |
| return findSliceItem(toQueue(s), new Filter<SliceItem>() { |
| @Override |
| public boolean filter(SliceItem item) { |
| return checkFormat(item, format) && checkSubtype(item, subtype); |
| } |
| }); |
| } |
| |
| /** |
| */ |
| public static SliceItem findSubtype(SliceItem s, final String format, final String subtype) { |
| if (s == null) return null; |
| return findSliceItem(toQueue(s), new Filter<SliceItem>() { |
| @Override |
| public boolean filter(SliceItem item) { |
| return checkFormat(item, format) && checkSubtype(item, subtype); |
| } |
| }); |
| } |
| |
| /** |
| */ |
| public static SliceItem find(SliceItem s, final String format, final String[] hints, |
| final String[] nonHints) { |
| if (s == null) return null; |
| return findSliceItem(toQueue(s), new Filter<SliceItem>() { |
| @Override |
| public boolean filter(SliceItem item) { |
| return checkFormat(item, format) |
| && (hasHints(item, hints) && !hasAnyHints(item, nonHints)); |
| } |
| }); |
| } |
| |
| @SuppressWarnings("WeakerAccess") /* synthetic access */ |
| static boolean checkFormat(SliceItem item, String format) { |
| return format == null || format.equals(item.getFormat()); |
| } |
| |
| @SuppressWarnings("WeakerAccess") /* synthetic access */ |
| static boolean checkSubtype(SliceItem item, String subtype) { |
| return subtype == null || subtype.equals(item.getSubType()); |
| } |
| |
| private static Deque<SliceItem> toQueue(Slice item) { |
| Deque<SliceItem> q = new ArrayDeque<>(); |
| Collections.addAll(q, item.getItemArray()); |
| return q; |
| } |
| |
| private static Deque<SliceItem> toQueue(SliceItem item) { |
| Deque<SliceItem> q = new ArrayDeque<>(); |
| q.add(item); |
| return q; |
| } |
| |
| private static SliceItem findSliceItem(final Deque<SliceItem> items, Filter<SliceItem> f) { |
| while (!items.isEmpty()) { |
| SliceItem item = items.poll(); |
| if (f.filter(item)) { |
| return item; |
| } |
| if (FORMAT_SLICE.equals(item.getFormat()) |
| || FORMAT_ACTION.equals(item.getFormat())) { |
| Collections.addAll(items, item.getSlice().getItemArray()); |
| } |
| } |
| return null; |
| } |
| |
| private static void findAll(final Deque<SliceItem> items, Filter<SliceItem> f, |
| List<SliceItem> out) { |
| while (!items.isEmpty()) { |
| SliceItem item = items.poll(); |
| if (f.filter(item)) { |
| out.add(item); |
| } |
| if (FORMAT_SLICE.equals(item.getFormat()) |
| || FORMAT_ACTION.equals(item.getFormat())) { |
| Collections.addAll(items, item.getSlice().getItemArray()); |
| } |
| } |
| } |
| |
| /** |
| * Finds an item matching provided params that is a direct child of the slice. |
| */ |
| public static SliceItem findTopLevelItem(Slice s, final String format, final String subtype, |
| final String[] hints, final String[] nonHints) { |
| SliceItem[] items = s.getItemArray(); |
| for (int i = 0; i < items.length; i++) { |
| SliceItem item = items[i]; |
| if (checkFormat(item, format) |
| && checkSubtype(item, subtype) |
| && hasHints(item, hints) |
| && !hasAnyHints(item, nonHints)) { |
| return item; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) |
| public static SliceItem findItem(Slice s, final Uri uri) { |
| return findSliceItem(toQueue(s), new Filter<SliceItem>() { |
| @Override |
| public boolean filter(SliceItem input) { |
| if (FORMAT_ACTION.equals(input.getFormat()) || FORMAT_SLICE.equals( |
| input.getFormat())) { |
| return uri.equals(input.getSlice().getUri()); |
| } |
| return false; |
| } |
| }); |
| } |
| |
| private interface Filter<T> { |
| boolean filter(T input); |
| } |
| |
| private SliceQuery() { |
| } |
| } |