1d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk/*
2d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk * Copyright (C) 2017 The Android Open Source Project
3d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk *
4d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk * Licensed under the Apache License, Version 2.0 (the "License");
5d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk * you may not use this file except in compliance with the License.
6d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk * You may obtain a copy of the License at
7d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk *
8d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk *      http://www.apache.org/licenses/LICENSE-2.0
9d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk *
10d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk * Unless required by applicable law or agreed to in writing, software
11d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk * distributed under the License is distributed on an "AS IS" BASIS,
12d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk * See the License for the specific language governing permissions and
14d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk * limitations under the License.
15d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk */
16d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk
17d18651fa892b70afd21ded4ee56e1f2e3e7614c6Jason Monkpackage android.app.slice;
18d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk
19d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monkimport java.util.Iterator;
20d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monkimport java.util.LinkedList;
21d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monkimport java.util.List;
22d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monkimport java.util.Objects;
23d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monkimport java.util.Queue;
24d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monkimport java.util.Spliterators;
25d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monkimport java.util.stream.Collectors;
26d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monkimport java.util.stream.Stream;
27d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monkimport java.util.stream.StreamSupport;
28d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk
29d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk/**
30d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk * A bunch of utilities for searching the contents of a slice.
31d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk * @hide
32d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk */
33d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monkpublic class SliceQuery {
34d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    private static final String TAG = "SliceQuery";
35d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk
36d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    /**
37d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     * @hide
38d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     */
39800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor    public static SliceItem getPrimaryIcon(Slice slice) {
40800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor        for (SliceItem item : slice.getItems()) {
41d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk            if (Objects.equals(item.getFormat(), SliceItem.FORMAT_IMAGE)) {
42800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor                return item;
43800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor            }
44d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk            if (!(compareTypes(item, SliceItem.FORMAT_SLICE)
45d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk                    && item.hasHint(Slice.HINT_LIST))
46800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor                    && !item.hasHint(Slice.HINT_ACTIONS)
47800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor                    && !item.hasHint(Slice.HINT_LIST_ITEM)
48d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk                    && !compareTypes(item, SliceItem.FORMAT_ACTION)) {
49d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk                SliceItem icon = SliceQuery.find(item, SliceItem.FORMAT_IMAGE);
50800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor                if (icon != null) {
51800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor                    return icon;
52800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor                }
53800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor            }
54800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor        }
55800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor        return null;
56800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor    }
57800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor
58800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor    /**
59800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor     * @hide
60800ba36336d86fc8f26209cb30b845127133d7c2Mady Mellor     */
61d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    public static SliceItem findNotContaining(SliceItem container, List<SliceItem> list) {
62d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk        SliceItem ret = null;
63d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk        while (ret == null && list.size() != 0) {
64d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk            SliceItem remove = list.remove(0);
65d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk            if (!contains(container, remove)) {
66d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk                ret = remove;
67d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk            }
68d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk        }
69d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk        return ret;
70d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    }
71d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk
72d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    /**
73d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     * @hide
74d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     */
75d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    private static boolean contains(SliceItem container, SliceItem item) {
76d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk        if (container == null || item == null) return false;
77d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk        return stream(container).filter(s -> (s == item)).findAny().isPresent();
78d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    }
79d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk
80d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    /**
81d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     * @hide
82d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     */
83d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk    public static List<SliceItem> findAll(SliceItem s, String type) {
844575aa52d7736ab51a4f72f5852b98d357783839Mady Mellor        return findAll(s, type, (String[]) null, null);
854575aa52d7736ab51a4f72f5852b98d357783839Mady Mellor    }
864575aa52d7736ab51a4f72f5852b98d357783839Mady Mellor
874575aa52d7736ab51a4f72f5852b98d357783839Mady Mellor    /**
884575aa52d7736ab51a4f72f5852b98d357783839Mady Mellor     * @hide
894575aa52d7736ab51a4f72f5852b98d357783839Mady Mellor     */
90d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk    public static List<SliceItem> findAll(SliceItem s, String type, String hints, String nonHints) {
91d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk        return findAll(s, type, new String[]{ hints }, new String[]{ nonHints });
92d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    }
93d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk
94d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    /**
95d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     * @hide
96d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     */
97d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk    public static List<SliceItem> findAll(SliceItem s, String type, String[] hints,
98d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk            String[] nonHints) {
99d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk        return stream(s).filter(item -> compareTypes(item, type)
100d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk                && (item.hasHints(hints) && !item.hasAnyHints(nonHints)))
101d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk                .collect(Collectors.toList());
102d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    }
103d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk
104d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    /**
105d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     * @hide
106d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     */
107d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk    public static SliceItem find(Slice s, String type, String hints, String nonHints) {
108d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk        return find(s, type, new String[]{ hints }, new String[]{ nonHints });
109d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    }
110d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk
111d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    /**
112d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     * @hide
113d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     */
114d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk    public static SliceItem find(Slice s, String type) {
1154575aa52d7736ab51a4f72f5852b98d357783839Mady Mellor        return find(s, type, (String[]) null, null);
1164575aa52d7736ab51a4f72f5852b98d357783839Mady Mellor    }
1174575aa52d7736ab51a4f72f5852b98d357783839Mady Mellor
1184575aa52d7736ab51a4f72f5852b98d357783839Mady Mellor    /**
1194575aa52d7736ab51a4f72f5852b98d357783839Mady Mellor     * @hide
1204575aa52d7736ab51a4f72f5852b98d357783839Mady Mellor     */
121d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk    public static SliceItem find(SliceItem s, String type) {
122d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk        return find(s, type, (String[]) null, null);
123d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    }
124d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk
125d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    /**
126d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     * @hide
127d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     */
128d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk    public static SliceItem find(SliceItem s, String type, String hints, String nonHints) {
129d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk        return find(s, type, new String[]{ hints }, new String[]{ nonHints });
130d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    }
131d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk
132d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    /**
133d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     * @hide
134d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     */
135d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk    public static SliceItem find(Slice s, String type, String[] hints, String[] nonHints) {
136d18651fa892b70afd21ded4ee56e1f2e3e7614c6Jason Monk        List<String> h = s.getHints();
137d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk        return find(new SliceItem(s, SliceItem.FORMAT_SLICE, null, h.toArray(new String[h.size()])),
138d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk                type, hints, nonHints);
139d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    }
140d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk
141d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    /**
142d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     * @hide
143d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     */
144d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk    public static SliceItem find(SliceItem s, String type, String[] hints, String[] nonHints) {
145d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk        return stream(s).filter(item -> compareTypes(item, type)
146d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk                && (item.hasHints(hints) && !item.hasAnyHints(nonHints))).findFirst().orElse(null);
147d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    }
148d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk
149d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    /**
150d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     * @hide
151d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk     */
152d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    public static Stream<SliceItem> stream(SliceItem slice) {
153d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk        Queue<SliceItem> items = new LinkedList();
154d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk        items.add(slice);
155d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk        Iterator<SliceItem> iterator = new Iterator<SliceItem>() {
156d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk            @Override
157d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk            public boolean hasNext() {
158d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk                return items.size() != 0;
159d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk            }
160d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk
161d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk            @Override
162d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk            public SliceItem next() {
163d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk                SliceItem item = items.poll();
164d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk                if (compareTypes(item, SliceItem.FORMAT_SLICE)
165d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk                        || compareTypes(item, SliceItem.FORMAT_ACTION)) {
166d18651fa892b70afd21ded4ee56e1f2e3e7614c6Jason Monk                    items.addAll(item.getSlice().getItems());
167d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk                }
168d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk                return item;
169d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk            }
170d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk        };
171d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
172d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk    }
173d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk
174d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk    /**
175d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk     * @hide
176d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk     */
177d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk    public static boolean compareTypes(SliceItem item, String desiredType) {
178d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk        final int typeLength = desiredType.length();
179d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk        if (typeLength == 3 && desiredType.equals("*/*")) {
180d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk            return true;
181d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk        }
182d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk        if (item.getSubType() == null && desiredType.indexOf('/') < 0) {
183d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk            return item.getFormat().equals(desiredType);
184d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk        }
185d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk        return (item.getFormat() + "/" + item.getSubType())
186d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk                .matches(desiredType.replaceAll("\\*", ".*"));
187d054fb36c79e4d10c8d35e2518923dc6f7c85e50Jason Monk    }
188d9edfa94b0e2a3f294e8c6ad01d4403bb7a8b971Jason Monk}
189