1 /* 2 * Copyright (C) 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 android.app.slice; 18 19 import java.util.Iterator; 20 import java.util.LinkedList; 21 import java.util.List; 22 import java.util.Objects; 23 import java.util.Queue; 24 import java.util.Spliterators; 25 import java.util.stream.Collectors; 26 import java.util.stream.Stream; 27 import java.util.stream.StreamSupport; 28 29 /** 30 * A bunch of utilities for searching the contents of a slice. 31 * @hide 32 */ 33 public class SliceQuery { 34 private static final String TAG = "SliceQuery"; 35 36 /** 37 * @hide 38 */ getPrimaryIcon(Slice slice)39 public static SliceItem getPrimaryIcon(Slice slice) { 40 for (SliceItem item : slice.getItems()) { 41 if (Objects.equals(item.getFormat(), SliceItem.FORMAT_IMAGE)) { 42 return item; 43 } 44 if (!(compareTypes(item, SliceItem.FORMAT_SLICE) 45 && item.hasHint(Slice.HINT_LIST)) 46 && !item.hasHint(Slice.HINT_ACTIONS) 47 && !item.hasHint(Slice.HINT_LIST_ITEM) 48 && !compareTypes(item, SliceItem.FORMAT_ACTION)) { 49 SliceItem icon = SliceQuery.find(item, SliceItem.FORMAT_IMAGE); 50 if (icon != null) { 51 return icon; 52 } 53 } 54 } 55 return null; 56 } 57 58 /** 59 * @hide 60 */ findNotContaining(SliceItem container, List<SliceItem> list)61 public static SliceItem findNotContaining(SliceItem container, List<SliceItem> list) { 62 SliceItem ret = null; 63 while (ret == null && list.size() != 0) { 64 SliceItem remove = list.remove(0); 65 if (!contains(container, remove)) { 66 ret = remove; 67 } 68 } 69 return ret; 70 } 71 72 /** 73 * @hide 74 */ contains(SliceItem container, SliceItem item)75 private static boolean contains(SliceItem container, SliceItem item) { 76 if (container == null || item == null) return false; 77 return stream(container).filter(s -> (s == item)).findAny().isPresent(); 78 } 79 80 /** 81 * @hide 82 */ findAll(SliceItem s, String type)83 public static List<SliceItem> findAll(SliceItem s, String type) { 84 return findAll(s, type, (String[]) null, null); 85 } 86 87 /** 88 * @hide 89 */ findAll(SliceItem s, String type, String hints, String nonHints)90 public static List<SliceItem> findAll(SliceItem s, String type, String hints, String nonHints) { 91 return findAll(s, type, new String[]{ hints }, new String[]{ nonHints }); 92 } 93 94 /** 95 * @hide 96 */ findAll(SliceItem s, String type, String[] hints, String[] nonHints)97 public static List<SliceItem> findAll(SliceItem s, String type, String[] hints, 98 String[] nonHints) { 99 return stream(s).filter(item -> compareTypes(item, type) 100 && (item.hasHints(hints) && !item.hasAnyHints(nonHints))) 101 .collect(Collectors.toList()); 102 } 103 104 /** 105 * @hide 106 */ find(Slice s, String type, String hints, String nonHints)107 public static SliceItem find(Slice s, String type, String hints, String nonHints) { 108 return find(s, type, new String[]{ hints }, new String[]{ nonHints }); 109 } 110 111 /** 112 * @hide 113 */ find(Slice s, String type)114 public static SliceItem find(Slice s, String type) { 115 return find(s, type, (String[]) null, null); 116 } 117 118 /** 119 * @hide 120 */ find(SliceItem s, String type)121 public static SliceItem find(SliceItem s, String type) { 122 return find(s, type, (String[]) null, null); 123 } 124 125 /** 126 * @hide 127 */ find(SliceItem s, String type, String hints, String nonHints)128 public static SliceItem find(SliceItem s, String type, String hints, String nonHints) { 129 return find(s, type, new String[]{ hints }, new String[]{ nonHints }); 130 } 131 132 /** 133 * @hide 134 */ find(Slice s, String type, String[] hints, String[] nonHints)135 public static SliceItem find(Slice s, String type, String[] hints, String[] nonHints) { 136 List<String> h = s.getHints(); 137 return find(new SliceItem(s, SliceItem.FORMAT_SLICE, null, h.toArray(new String[h.size()])), 138 type, hints, nonHints); 139 } 140 141 /** 142 * @hide 143 */ find(SliceItem s, String type, String[] hints, String[] nonHints)144 public static SliceItem find(SliceItem s, String type, String[] hints, String[] nonHints) { 145 return stream(s).filter(item -> compareTypes(item, type) 146 && (item.hasHints(hints) && !item.hasAnyHints(nonHints))).findFirst().orElse(null); 147 } 148 149 /** 150 * @hide 151 */ stream(SliceItem slice)152 public static Stream<SliceItem> stream(SliceItem slice) { 153 Queue<SliceItem> items = new LinkedList(); 154 items.add(slice); 155 Iterator<SliceItem> iterator = new Iterator<SliceItem>() { 156 @Override 157 public boolean hasNext() { 158 return items.size() != 0; 159 } 160 161 @Override 162 public SliceItem next() { 163 SliceItem item = items.poll(); 164 if (compareTypes(item, SliceItem.FORMAT_SLICE) 165 || compareTypes(item, SliceItem.FORMAT_ACTION)) { 166 items.addAll(item.getSlice().getItems()); 167 } 168 return item; 169 } 170 }; 171 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false); 172 } 173 174 /** 175 * @hide 176 */ compareTypes(SliceItem item, String desiredType)177 public static boolean compareTypes(SliceItem item, String desiredType) { 178 final int typeLength = desiredType.length(); 179 if (typeLength == 3 && desiredType.equals("*/*")) { 180 return true; 181 } 182 if (item.getSubType() == null && desiredType.indexOf('/') < 0) { 183 return item.getFormat().equals(desiredType); 184 } 185 return (item.getFormat() + "/" + item.getSubType()) 186 .matches(desiredType.replaceAll("\\*", ".*")); 187 } 188 } 189