blob: 51517e017deabae867eceadf5d4f62a6ef60ff47 [file] [log] [blame]
Jason Monkdcb5e2f2017-11-15 20:19:43 -05001/*
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
17package androidx.app.slice;
18
19import static android.app.slice.SliceItem.FORMAT_ACTION;
20import static android.app.slice.SliceItem.FORMAT_COLOR;
21import static android.app.slice.SliceItem.FORMAT_IMAGE;
22import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
23import static android.app.slice.SliceItem.FORMAT_SLICE;
24import static android.app.slice.SliceItem.FORMAT_TEXT;
25import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
26
27import android.app.PendingIntent;
28import android.app.RemoteInput;
29import android.graphics.drawable.Icon;
30import android.os.Bundle;
31import android.os.Parcelable;
32import android.support.annotation.NonNull;
Jason Monk2a7d0fc2017-11-15 10:10:24 -050033import android.support.annotation.RequiresApi;
Jason Monkdcb5e2f2017-11-15 20:19:43 -050034import android.support.annotation.RestrictTo;
35import android.support.annotation.RestrictTo.Scope;
36import android.support.annotation.StringDef;
37import android.text.TextUtils;
38import android.util.Pair;
39
40import java.util.Arrays;
41import java.util.List;
42
43
44/**
45 * A SliceItem is a single unit in the tree structure of a {@link Slice}.
46 * <p>
47 * A SliceItem a piece of content and some hints about what that content
48 * means or how it should be displayed. The types of content can be:
49 * <li>{@link android.app.slice.SliceItem#FORMAT_SLICE}</li>
50 * <li>{@link android.app.slice.SliceItem#FORMAT_TEXT}</li>
51 * <li>{@link android.app.slice.SliceItem#FORMAT_IMAGE}</li>
52 * <li>{@link android.app.slice.SliceItem#FORMAT_ACTION}</li>
53 * <li>{@link android.app.slice.SliceItem#FORMAT_COLOR}</li>
54 * <li>{@link android.app.slice.SliceItem#FORMAT_TIMESTAMP}</li>
55 * <li>{@link android.app.slice.SliceItem#FORMAT_REMOTE_INPUT}</li>
56 * <p>
57 * The hints that a {@link SliceItem} are a set of strings which annotate
58 * the content. The hints that are guaranteed to be understood by the system
59 * are defined on {@link Slice}.
60 */
61public class SliceItem {
62
63 private static final String HINTS = "hints";
64 private static final String FORMAT = "format";
65 private static final String SUBTYPE = "subtype";
66 private static final String OBJ = "obj";
67 private static final String OBJ_2 = "obj_2";
68
69 /**
70 * @hide
71 */
72 @RestrictTo(Scope.LIBRARY)
73 @StringDef({FORMAT_SLICE, FORMAT_TEXT, FORMAT_IMAGE, FORMAT_ACTION, FORMAT_COLOR,
74 FORMAT_TIMESTAMP, FORMAT_REMOTE_INPUT})
75 public @interface SliceType {
76 }
77
78 /**
79 * @hide
80 */
81 @RestrictTo(Scope.LIBRARY)
82 protected @Slice.SliceHint String[] mHints;
83 private final String mFormat;
84 private final String mSubType;
85 private final Object mObj;
86
87 /**
88 * @hide
89 */
90 @RestrictTo(Scope.LIBRARY)
91 public SliceItem(Object obj, @SliceType String format, String subType,
92 @Slice.SliceHint String[] hints) {
93 mHints = hints;
94 mFormat = format;
95 mSubType = subType;
96 mObj = obj;
97 }
98
99 /**
100 * @hide
101 */
102 @RestrictTo(Scope.LIBRARY)
103 public SliceItem(PendingIntent intent, Slice slice, String format, String subType,
104 @Slice.SliceHint String[] hints) {
105 this(new Pair<>(intent, slice), format, subType, hints);
106 }
107
108 /**
109 * Gets all hints associated with this SliceItem.
110 *
111 * @return Array of hints.
112 */
113 public @NonNull @Slice.SliceHint List<String> getHints() {
114 return Arrays.asList(mHints);
115 }
116
117 /**
118 * @hide
119 */
120 @RestrictTo(Scope.LIBRARY)
121 public void addHint(@Slice.SliceHint String hint) {
122 mHints = ArrayUtils.appendElement(String.class, mHints, hint);
123 }
124
125 /**
126 * @hide
127 */
128 @RestrictTo(Scope.LIBRARY)
129 public void removeHint(String hint) {
130 ArrayUtils.removeElement(String.class, mHints, hint);
131 }
132
133 /**
134 * Get the format of this SliceItem.
135 * <p>
136 * The format will be one of the following types supported by the platform:
137 * <li>{@link android.app.slice.SliceItem#FORMAT_SLICE}</li>
138 * <li>{@link android.app.slice.SliceItem#FORMAT_TEXT}</li>
139 * <li>{@link android.app.slice.SliceItem#FORMAT_IMAGE}</li>
140 * <li>{@link android.app.slice.SliceItem#FORMAT_ACTION}</li>
141 * <li>{@link android.app.slice.SliceItem#FORMAT_COLOR}</li>
142 * <li>{@link android.app.slice.SliceItem#FORMAT_TIMESTAMP}</li>
143 * <li>{@link android.app.slice.SliceItem#FORMAT_REMOTE_INPUT}</li>
144 * @see #getSubType() ()
145 */
146 public @SliceType String getFormat() {
147 return mFormat;
148 }
149
150 /**
151 * Get the sub-type of this SliceItem.
152 * <p>
153 * Subtypes provide additional information about the type of this information beyond basic
154 * interpretations inferred by {@link #getFormat()}. For example a slice may contain
155 * many {@link android.app.slice.SliceItem#FORMAT_TEXT} items, but only some of them may be
156 * {@link android.app.slice.Slice#SUBTYPE_MESSAGE}.
157 * @see #getFormat()
158 */
159 public String getSubType() {
160 return mSubType;
161 }
162
163 /**
164 * @return The text held by this {@link android.app.slice.SliceItem#FORMAT_TEXT} SliceItem
165 */
166 public CharSequence getText() {
167 return (CharSequence) mObj;
168 }
169
170 /**
171 * @return The icon held by this {@link android.app.slice.SliceItem#FORMAT_IMAGE} SliceItem
172 */
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500173 @RequiresApi(23)
Jason Monkdcb5e2f2017-11-15 20:19:43 -0500174 public Icon getIcon() {
175 return (Icon) mObj;
176 }
177
178 /**
179 * @return The pending intent held by this {@link android.app.slice.SliceItem#FORMAT_ACTION}
180 * SliceItem
181 */
182 public PendingIntent getAction() {
183 return ((Pair<PendingIntent, Slice>) mObj).first;
184 }
185
186 /**
187 * @return The remote input held by this {@link android.app.slice.SliceItem#FORMAT_REMOTE_INPUT}
188 * SliceItem
189 */
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500190 @RequiresApi(20)
Jason Monkdcb5e2f2017-11-15 20:19:43 -0500191 public RemoteInput getRemoteInput() {
192 return (RemoteInput) mObj;
193 }
194
195 /**
196 * @return The color held by this {@link android.app.slice.SliceItem#FORMAT_COLOR} SliceItem
197 */
198 public int getColor() {
199 return (Integer) mObj;
200 }
201
202 /**
203 * @return The slice held by this {@link android.app.slice.SliceItem#FORMAT_ACTION} or
204 * {@link android.app.slice.SliceItem#FORMAT_SLICE} SliceItem
205 */
206 public Slice getSlice() {
207 if (FORMAT_ACTION.equals(getFormat())) {
208 return ((Pair<PendingIntent, Slice>) mObj).second;
209 }
210 return (Slice) mObj;
211 }
212
213 /**
214 * @return The timestamp held by this {@link android.app.slice.SliceItem#FORMAT_TIMESTAMP}
215 * SliceItem
216 */
217 public long getTimestamp() {
218 return (Long) mObj;
219 }
220
221 /**
222 * @param hint The hint to check for
223 * @return true if this item contains the given hint
224 */
225 public boolean hasHint(@Slice.SliceHint String hint) {
226 return ArrayUtils.contains(mHints, hint);
227 }
228
229 /**
230 * @hide
231 */
232 @RestrictTo(Scope.LIBRARY)
233 public SliceItem(Bundle in) {
234 mHints = in.getStringArray(HINTS);
235 mFormat = in.getString(FORMAT);
236 mSubType = in.getString(SUBTYPE);
237 mObj = readObj(mFormat, in);
238 }
239
240 /**
241 * @hide
242 * @return
243 */
244 @RestrictTo(Scope.LIBRARY)
245 public Bundle toBundle() {
246 Bundle b = new Bundle();
247 b.putStringArray(HINTS, mHints);
248 b.putString(FORMAT, mFormat);
249 b.putString(SUBTYPE, mSubType);
250 writeObj(b, mObj, mFormat);
251 return b;
252 }
253
254 /**
255 * @hide
256 */
257 @RestrictTo(Scope.LIBRARY)
258 public boolean hasHints(@Slice.SliceHint String[] hints) {
259 if (hints == null) return true;
260 for (String hint : hints) {
261 if (!TextUtils.isEmpty(hint) && !ArrayUtils.contains(mHints, hint)) {
262 return false;
263 }
264 }
265 return true;
266 }
267
268 /**
269 * @hide
270 */
271 @RestrictTo(Scope.LIBRARY)
Mady Mellor71ef84d2017-12-11 13:33:36 -0800272 public boolean hasAnyHints(@Slice.SliceHint String... hints) {
Jason Monkdcb5e2f2017-11-15 20:19:43 -0500273 if (hints == null) return false;
274 for (String hint : hints) {
275 if (ArrayUtils.contains(mHints, hint)) {
276 return true;
277 }
278 }
279 return false;
280 }
281
282 private void writeObj(Bundle dest, Object obj, String type) {
283 switch (type) {
284 case FORMAT_IMAGE:
285 case FORMAT_REMOTE_INPUT:
286 dest.putParcelable(OBJ, (Parcelable) obj);
287 break;
288 case FORMAT_SLICE:
289 dest.putParcelable(OBJ, ((Slice) obj).toBundle());
290 break;
291 case FORMAT_ACTION:
292 dest.putParcelable(OBJ, ((Pair<PendingIntent, Slice>) obj).first);
293 dest.putBundle(OBJ_2, ((Pair<PendingIntent, Slice>) obj).second.toBundle());
294 break;
295 case FORMAT_TEXT:
296 dest.putCharSequence(OBJ, (CharSequence) obj);
297 break;
298 case FORMAT_COLOR:
299 dest.putInt(OBJ, (Integer) mObj);
300 break;
301 case FORMAT_TIMESTAMP:
302 dest.putLong(OBJ, (Long) mObj);
303 break;
304 }
305 }
306
307 private static Object readObj(String type, Bundle in) {
308 switch (type) {
309 case FORMAT_IMAGE:
310 case FORMAT_REMOTE_INPUT:
311 return in.getParcelable(OBJ);
312 case FORMAT_SLICE:
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500313 return new Slice(in.getBundle(OBJ));
Jason Monkdcb5e2f2017-11-15 20:19:43 -0500314 case FORMAT_TEXT:
315 return in.getCharSequence(OBJ);
316 case FORMAT_ACTION:
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500317 return new Pair<>(
318 (PendingIntent) in.getParcelable(OBJ),
Jason Monkdcb5e2f2017-11-15 20:19:43 -0500319 new Slice(in.getBundle(OBJ_2)));
320 case FORMAT_COLOR:
321 return in.getInt(OBJ);
322 case FORMAT_TIMESTAMP:
323 return in.getLong(OBJ);
324 }
325 throw new RuntimeException("Unsupported type " + type);
326 }
327
328 /**
329 * @hide
330 */
331 @RestrictTo(Scope.LIBRARY)
332 public static String typeToString(String format) {
333 switch (format) {
334 case FORMAT_SLICE:
335 return "Slice";
336 case FORMAT_TEXT:
337 return "Text";
338 case FORMAT_IMAGE:
339 return "Image";
340 case FORMAT_ACTION:
341 return "Action";
342 case FORMAT_COLOR:
343 return "Color";
344 case FORMAT_TIMESTAMP:
345 return "Timestamp";
346 case FORMAT_REMOTE_INPUT:
347 return "RemoteInput";
348 }
349 return "Unrecognized format: " + format;
350 }
351}