• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.tv.twopanelsettings.slices.compat.core;
18 
19 import static android.app.slice.SliceItem.FORMAT_ACTION;
20 import static android.app.slice.SliceItem.FORMAT_SLICE;
21 
22 import android.net.Uri;
23 import android.text.TextUtils;
24 import androidx.annotation.NonNull;
25 import androidx.annotation.Nullable;
26 import com.android.tv.twopanelsettings.slices.compat.Slice;
27 import com.android.tv.twopanelsettings.slices.compat.SliceItem;
28 import java.util.ArrayDeque;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.Deque;
32 import java.util.List;
33 
34 /** Utilities for finding content within a Slice. */
35 // @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
36 // @Deprecated // Supported for TV
37 public class SliceQuery {
38 
39   /** */
hasAnyHints(@onNull SliceItem item, @Nullable String... hints)40   public static boolean hasAnyHints(@NonNull SliceItem item, @Nullable String... hints) {
41     if (hints == null) {
42       return false;
43     }
44     for (String hint : hints) {
45       if (item.hasHint(hint)) {
46         return true;
47       }
48     }
49     return false;
50   }
51 
52   /** */
hasHints(@onNull SliceItem item, @Nullable String... hints)53   public static boolean hasHints(@NonNull SliceItem item, @Nullable String... hints) {
54     if (hints == null) {
55       return true;
56     }
57     for (String hint : hints) {
58       if (!TextUtils.isEmpty(hint) && !item.hasHint(hint)) {
59         return false;
60       }
61     }
62     return true;
63   }
64 
65   /** */
66   @SuppressWarnings("unused")
hasHints(@onNull Slice item, @Nullable String... hints)67   public static boolean hasHints(@NonNull Slice item, @Nullable String... hints) {
68     if (hints == null) {
69       return true;
70     }
71     for (String hint : hints) {
72       if (!TextUtils.isEmpty(hint) && !item.hasHint(hint)) {
73         return false;
74       }
75     }
76     return true;
77   }
78 
79   /** */
80   @SuppressWarnings("unused")
81   @Nullable
findNotContaining( @ullable SliceItem container, @NonNull List<SliceItem> list)82   public static SliceItem findNotContaining(
83       @Nullable SliceItem container, @NonNull List<SliceItem> list) {
84     SliceItem ret = null;
85     while (ret == null && !list.isEmpty()) {
86       SliceItem remove = list.remove(0);
87       if (!contains(container, remove)) {
88         ret = remove;
89       }
90     }
91     return ret;
92   }
93 
94   /** */
contains(@ullable SliceItem container, @Nullable final SliceItem item)95   private static boolean contains(@Nullable SliceItem container, @Nullable final SliceItem item) {
96     if (container == null || item == null) {
97       return false;
98     }
99     return findSliceItem(toQueue(container), s -> s == item) != null;
100   }
101 
102   /** */
103   @NonNull
findAll(@onNull SliceItem s, @Nullable String format)104   public static List<SliceItem> findAll(@NonNull SliceItem s, @Nullable String format) {
105     return findAll(s, format, (String[]) null, null);
106   }
107 
108   /** */
109   @SuppressWarnings("unused")
110   @NonNull
findAll( @onNull Slice s, @Nullable String format, @Nullable String hints, @Nullable String nonHints)111   public static List<SliceItem> findAll(
112       @NonNull Slice s,
113       @Nullable String format,
114       @Nullable String hints,
115       @Nullable String nonHints) {
116     return findAll(s, format, new String[] {hints}, new String[] {nonHints});
117   }
118 
119   /** */
120   @NonNull
findAll( @onNull SliceItem s, @Nullable String format, @Nullable String hints, @Nullable String nonHints)121   public static List<SliceItem> findAll(
122       @NonNull SliceItem s,
123       @Nullable String format,
124       @Nullable String hints,
125       @Nullable String nonHints) {
126     return findAll(s, format, new String[] {hints}, new String[] {nonHints});
127   }
128 
129   /** */
130   @NonNull
findAll( @onNull Slice s, @Nullable final String format, @Nullable final String[] hints, @Nullable final String[] nonHints)131   public static List<SliceItem> findAll(
132       @NonNull Slice s,
133       @Nullable final String format,
134       @Nullable final String[] hints,
135       @Nullable final String[] nonHints) {
136     ArrayList<SliceItem> ret = new ArrayList<>();
137     findAll(
138         toQueue(s),
139         item ->
140             checkFormat(item, format) && (hasHints(item, hints) && !hasAnyHints(item, nonHints)),
141         ret);
142     return ret;
143   }
144 
145   /** */
146   @NonNull
findAll( @onNull SliceItem s, @Nullable final String format, @Nullable final String[] hints, @Nullable final String[] nonHints)147   public static List<SliceItem> findAll(
148       @NonNull SliceItem s,
149       @Nullable final String format,
150       @Nullable final String[] hints,
151       @Nullable final String[] nonHints) {
152     ArrayList<SliceItem> ret = new ArrayList<>();
153     findAll(
154         toQueue(s),
155         item ->
156             checkFormat(item, format) && (hasHints(item, hints) && !hasAnyHints(item, nonHints)),
157         ret);
158     return ret;
159   }
160 
161   /** */
162   @Nullable
find( @ullable Slice s, @Nullable String format, @Nullable String hints, @Nullable String nonHints)163   public static SliceItem find(
164       @Nullable Slice s,
165       @Nullable String format,
166       @Nullable String hints,
167       @Nullable String nonHints) {
168     return find(s, format, new String[] {hints}, new String[] {nonHints});
169   }
170 
171   /** */
172   @Nullable
find(@ullable Slice s, @Nullable String format)173   public static SliceItem find(@Nullable Slice s, @Nullable String format) {
174     return find(s, format, (String[]) null, null);
175   }
176 
177   /** */
178   @Nullable
find(@ullable SliceItem s, @Nullable String format)179   public static SliceItem find(@Nullable SliceItem s, @Nullable String format) {
180     return find(s, format, (String[]) null, null);
181   }
182 
183   /** */
184   @Nullable
find( @ullable SliceItem s, @Nullable String format, @Nullable String hints, @Nullable String nonHints)185   public static SliceItem find(
186       @Nullable SliceItem s,
187       @Nullable String format,
188       @Nullable String hints,
189       @Nullable String nonHints) {
190     return find(s, format, new String[] {hints}, new String[] {nonHints});
191   }
192 
193   /** */
194   @Nullable
find( @ullable Slice s, @Nullable final String format, @Nullable final String[] hints, @Nullable final String[] nonHints)195   public static SliceItem find(
196       @Nullable Slice s,
197       @Nullable final String format,
198       @Nullable final String[] hints,
199       @Nullable final String[] nonHints) {
200     if (s == null) {
201       return null;
202     }
203     return findSliceItem(
204         toQueue(s),
205         item ->
206             checkFormat(item, format) && (hasHints(item, hints) && !hasAnyHints(item, nonHints)));
207   }
208 
209   /** */
210   @Nullable
findSubtype( @ullable Slice s, @Nullable final String format, @Nullable final String subtype)211   public static SliceItem findSubtype(
212       @Nullable Slice s, @Nullable final String format, @Nullable final String subtype) {
213     if (s == null) {
214       return null;
215     }
216     return findSliceItem(
217         toQueue(s), item -> checkFormat(item, format) && checkSubtype(item, subtype));
218   }
219 
220   /** */
221   @Nullable
findSubtype( @ullable SliceItem s, @Nullable final String format, @Nullable final String subtype)222   public static SliceItem findSubtype(
223       @Nullable SliceItem s, @Nullable final String format, @Nullable final String subtype) {
224     if (s == null) {
225       return null;
226     }
227     return findSliceItem(
228         toQueue(s), item -> checkFormat(item, format) && checkSubtype(item, subtype));
229   }
230 
231   /** */
232   @Nullable
find( @ullable SliceItem s, @Nullable final String format, @Nullable final String[] hints, @Nullable final String[] nonHints)233   public static SliceItem find(
234       @Nullable SliceItem s,
235       @Nullable final String format,
236       @Nullable final String[] hints,
237       @Nullable final String[] nonHints) {
238     if (s == null) {
239       return null;
240     }
241     return findSliceItem(
242         toQueue(s),
243         item ->
244             checkFormat(item, format) && (hasHints(item, hints) && !hasAnyHints(item, nonHints)));
245   }
246 
247   @SuppressWarnings("WeakerAccess") /* synthetic access */
checkFormat(@onNull SliceItem item, @Nullable String format)248   static boolean checkFormat(@NonNull SliceItem item, @Nullable String format) {
249     return format == null || format.equals(item.getFormat());
250   }
251 
252   @SuppressWarnings("WeakerAccess") /* synthetic access */
checkSubtype(@onNull SliceItem item, @Nullable String subtype)253   static boolean checkSubtype(@NonNull SliceItem item, @Nullable String subtype) {
254     return subtype == null || subtype.equals(item.getSubType());
255   }
256 
toQueue(@onNull Slice item)257   private static @NonNull Deque<SliceItem> toQueue(@NonNull Slice item) {
258     Deque<SliceItem> q = new ArrayDeque<>();
259     Collections.addAll(q, item.getItemArray());
260     return q;
261   }
262 
toQueue(@onNull SliceItem item)263   private static @NonNull Deque<SliceItem> toQueue(@NonNull SliceItem item) {
264     Deque<SliceItem> q = new ArrayDeque<>();
265     q.add(item);
266     return q;
267   }
268 
269   @Nullable
findSliceItem( @onNull final Deque<SliceItem> items, @NonNull Filter<SliceItem> f)270   private static SliceItem findSliceItem(
271       @NonNull final Deque<SliceItem> items, @NonNull Filter<SliceItem> f) {
272     while (!items.isEmpty()) {
273       SliceItem item = items.poll();
274       if (f.filter(item)) {
275         return item;
276       }
277       if (item != null
278           && (FORMAT_SLICE.equals(item.getFormat()) || FORMAT_ACTION.equals(item.getFormat()))) {
279         Collections.addAll(items, item.getSlice().getItemArray());
280       }
281     }
282     return null;
283   }
284 
findAll( @onNull final Deque<SliceItem> items, @NonNull Filter<SliceItem> f, @NonNull List<SliceItem> out)285   private static void findAll(
286       @NonNull final Deque<SliceItem> items,
287       @NonNull Filter<SliceItem> f,
288       @NonNull List<SliceItem> out) {
289     while (!items.isEmpty()) {
290       SliceItem item = items.poll();
291       if (f.filter(item)) {
292         out.add(item);
293       }
294       if (item != null
295           && (FORMAT_SLICE.equals(item.getFormat()) || FORMAT_ACTION.equals(item.getFormat()))) {
296         Collections.addAll(items, item.getSlice().getItemArray());
297       }
298     }
299   }
300 
301   /** Finds an item matching provided params that is a direct child of the slice. */
302   @Nullable
findTopLevelItem( @onNull Slice s, @Nullable final String format, @Nullable final String subtype, @Nullable final String[] hints, @Nullable final String[] nonHints)303   public static SliceItem findTopLevelItem(
304       @NonNull Slice s,
305       @Nullable final String format,
306       @Nullable final String subtype,
307       @Nullable final String[] hints,
308       @Nullable final String[] nonHints) {
309     SliceItem[] items = s.getItemArray();
310     for (SliceItem item : items) {
311       if (checkFormat(item, format)
312           && checkSubtype(item, subtype)
313           && hasHints(item, hints)
314           && !hasAnyHints(item, nonHints)) {
315         return item;
316       }
317     }
318     return null;
319   }
320 
321   /** */
322   @Nullable
findItem(@onNull Slice s, @NonNull final Uri uri)323   public static SliceItem findItem(@NonNull Slice s, @NonNull final Uri uri) {
324     return findSliceItem(
325         toQueue(s),
326         input -> {
327           if (FORMAT_ACTION.equals(input.getFormat()) || FORMAT_SLICE.equals(input.getFormat())) {
328             return uri.equals(input.getSlice().getUri());
329           }
330           return false;
331         });
332   }
333 
334   private interface Filter<T> {
335     boolean filter(T input);
336   }
337 
338   private SliceQuery() {}
339 }
340