1 /* 2 * Copyright 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.slice.core; 18 19 import static android.app.slice.SliceItem.FORMAT_ACTION; 20 import static android.app.slice.SliceItem.FORMAT_SLICE; 21 22 import android.text.TextUtils; 23 24 import androidx.annotation.RestrictTo; 25 import androidx.slice.Slice; 26 import androidx.slice.SliceItem; 27 28 import java.util.ArrayList; 29 import java.util.Iterator; 30 import java.util.List; 31 32 /** 33 * Utilities for finding content within a Slice. 34 * @hide 35 */ 36 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 37 public class SliceQuery { 38 39 /** 40 */ 41 public static boolean hasAnyHints(SliceItem item, String... hints) { 42 if (hints == null) return false; 43 List<String> itemHints = item.getHints(); 44 for (String hint : hints) { 45 if (itemHints.contains(hint)) { 46 return true; 47 } 48 } 49 return false; 50 } 51 52 /** 53 */ 54 public static boolean hasHints(SliceItem item, String... hints) { 55 if (hints == null) return true; 56 List<String> itemHints = item.getHints(); 57 for (String hint : hints) { 58 if (!TextUtils.isEmpty(hint) && !itemHints.contains(hint)) { 59 return false; 60 } 61 } 62 return true; 63 } 64 65 /** 66 */ 67 public static boolean hasHints(Slice item, String... hints) { 68 if (hints == null) return true; 69 List<String> itemHints = item.getHints(); 70 for (String hint : hints) { 71 if (!TextUtils.isEmpty(hint) && !itemHints.contains(hint)) { 72 return false; 73 } 74 } 75 return true; 76 } 77 78 /** 79 */ 80 public static SliceItem findNotContaining(SliceItem container, List<SliceItem> list) { 81 SliceItem ret = null; 82 while (ret == null && list.size() != 0) { 83 SliceItem remove = list.remove(0); 84 if (!contains(container, remove)) { 85 ret = remove; 86 } 87 } 88 return ret; 89 } 90 91 /** 92 */ 93 private static boolean contains(SliceItem container, final SliceItem item) { 94 if (container == null || item == null) return false; 95 return findFirst(filter(stream(container), new Filter<SliceItem>() { 96 @Override 97 public boolean filter(SliceItem s) { 98 return s == item; 99 } 100 }), null) != null; 101 } 102 103 /** 104 */ 105 public static List<SliceItem> findAll(SliceItem s, String format) { 106 return findAll(s, format, (String[]) null, null); 107 } 108 109 /** 110 */ 111 public static List<SliceItem> findAll(Slice s, String format, String hints, String nonHints) { 112 return findAll(s, format, new String[]{ hints }, new String[]{ nonHints }); 113 } 114 115 /** 116 */ 117 public static List<SliceItem> findAll(SliceItem s, String format, String hints, 118 String nonHints) { 119 return findAll(s, format, new String[]{ hints }, new String[]{ nonHints }); 120 } 121 122 /** 123 */ 124 public static List<SliceItem> findAll(Slice s, final String format, final String[] hints, 125 final String[] nonHints) { 126 return collect(filter(stream(s), new Filter<SliceItem>() { 127 @Override 128 public boolean filter(SliceItem item) { 129 return checkFormat(item, format) 130 && (hasHints(item, hints) && !hasAnyHints(item, nonHints)); 131 } 132 })); 133 } 134 135 /** 136 */ 137 public static List<SliceItem> findAll(SliceItem s, final String format, final String[] hints, 138 final String[] nonHints) { 139 return collect(filter(stream(s), new Filter<SliceItem>() { 140 @Override 141 public boolean filter(SliceItem item) { 142 return checkFormat(item, format) 143 && (hasHints(item, hints) && !hasAnyHints(item, nonHints)); 144 } 145 })); 146 } 147 148 /** 149 */ 150 public static SliceItem find(Slice s, String format, String hints, String nonHints) { 151 return find(s, format, new String[]{ hints }, new String[]{ nonHints }); 152 } 153 154 /** 155 */ 156 public static SliceItem find(Slice s, String format) { 157 return find(s, format, (String[]) null, null); 158 } 159 160 /** 161 */ 162 public static SliceItem find(SliceItem s, String format) { 163 return find(s, format, (String[]) null, null); 164 } 165 166 /** 167 */ 168 public static SliceItem find(SliceItem s, String format, String hints, String nonHints) { 169 return find(s, format, new String[]{ hints }, new String[]{ nonHints }); 170 } 171 172 /** 173 */ 174 public static SliceItem find(Slice s, final String format, final String[] hints, 175 final String[] nonHints) { 176 return findFirst(filter(stream(s), new Filter<SliceItem>() { 177 @Override 178 public boolean filter(SliceItem item) { 179 return checkFormat(item, format) 180 && (hasHints(item, hints) && !hasAnyHints(item, nonHints)); 181 } 182 }), null); 183 } 184 185 /** 186 */ 187 public static SliceItem findSubtype(Slice s, final String format, final String subtype) { 188 return findFirst(filter(stream(s), new Filter<SliceItem>() { 189 @Override 190 public boolean filter(SliceItem item) { 191 return checkFormat(item, format) && checkSubtype(item, subtype); 192 } 193 }), null); 194 } 195 196 /** 197 */ 198 public static SliceItem findSubtype(SliceItem s, final String format, final String subtype) { 199 return findFirst(filter(stream(s), new Filter<SliceItem>() { 200 @Override 201 public boolean filter(SliceItem item) { 202 return checkFormat(item, format) && checkSubtype(item, subtype); 203 } 204 }), null); 205 } 206 207 /** 208 */ 209 public static SliceItem find(SliceItem s, final String format, final String[] hints, 210 final String[] nonHints) { 211 return findFirst(filter(stream(s), new Filter<SliceItem>() { 212 @Override 213 public boolean filter(SliceItem item) { 214 return checkFormat(item, format) 215 && (hasHints(item, hints) && !hasAnyHints(item, nonHints)); 216 } 217 }), null); 218 } 219 220 private static boolean checkFormat(SliceItem item, String format) { 221 return format == null || format.equals(item.getFormat()); 222 } 223 224 private static boolean checkSubtype(SliceItem item, String subtype) { 225 return subtype == null || subtype.equals(item.getSubType()); 226 } 227 228 /** 229 */ 230 public static Iterator<SliceItem> stream(SliceItem slice) { 231 ArrayList<SliceItem> items = new ArrayList<>(); 232 items.add(slice); 233 return getSliceItemStream(items); 234 } 235 236 /** 237 */ 238 public static Iterator<SliceItem> stream(Slice slice) { 239 ArrayList<SliceItem> items = new ArrayList<>(); 240 items.addAll(slice.getItems()); 241 return getSliceItemStream(items); 242 } 243 244 /** 245 */ 246 private static Iterator<SliceItem> getSliceItemStream(final ArrayList<SliceItem> items) { 247 return new Iterator<SliceItem>() { 248 @Override 249 public boolean hasNext() { 250 return items.size() != 0; 251 } 252 253 @Override 254 public SliceItem next() { 255 SliceItem item = items.remove(0); 256 if (FORMAT_SLICE.equals(item.getFormat()) 257 || FORMAT_ACTION.equals(item.getFormat())) { 258 items.addAll(item.getSlice().getItems()); 259 } 260 return item; 261 } 262 }; 263 } 264 265 private static <T> List<T> collect(Iterator<T> iter) { 266 List<T> list = new ArrayList<>(); 267 while (iter.hasNext()) list.add(iter.next()); 268 return list; 269 } 270 271 private static <T> Iterator<T> filter(final Iterator<T> input, final Filter<T> f) { 272 return new Iterator<T>() { 273 T mNext = findNext(); 274 275 private T findNext() { 276 while (input.hasNext()) { 277 T i = input.next(); 278 if (f.filter(i)) { 279 return i; 280 } 281 } 282 return null; 283 } 284 285 @Override 286 public boolean hasNext() { 287 return mNext != null; 288 } 289 290 @Override 291 public T next() { 292 T ret = mNext; 293 mNext = findNext(); 294 return ret; 295 } 296 }; 297 } 298 299 private static <T> T findFirst(Iterator<T> filter, T def) { 300 while (filter.hasNext()) { 301 T r = filter.next(); 302 if (r != null) return r; 303 } 304 return def; 305 } 306 307 private interface Filter<T> { 308 boolean filter(T input); 309 } 310 311 private SliceQuery() { 312 } 313 } 314