blob: 019ae492663691a935f524d906c7786ec8f91073 [file] [log] [blame]
Jason Monkd9edfa942017-09-25 12:38:53 -04001/*
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
Jason Monkd18651f2017-10-05 14:18:49 -040017package android.app.slice;
Jason Monkd9edfa942017-09-25 12:38:53 -040018
Jason Monkd9edfa942017-09-25 12:38:53 -040019import android.annotation.NonNull;
Jason Monkd054fb32017-11-07 21:52:10 -050020import android.annotation.StringDef;
Jason Monkd9edfa942017-09-25 12:38:53 -040021import android.app.PendingIntent;
22import android.app.RemoteInput;
23import android.graphics.drawable.Icon;
Jason Monkfed72bf2017-12-08 18:19:32 -050024import android.os.Bundle;
Jason Monkd9edfa942017-09-25 12:38:53 -040025import android.os.Parcel;
26import android.os.Parcelable;
Jason Monkd9edfa942017-09-25 12:38:53 -040027import android.text.TextUtils;
28import android.util.Pair;
29import android.widget.RemoteViews;
30
31import com.android.internal.util.ArrayUtils;
32
Jeff Sharkey5db9a912017-12-08 17:32:32 -070033import java.lang.annotation.Retention;
34import java.lang.annotation.RetentionPolicy;
Jason Monkd18651f2017-10-05 14:18:49 -040035import java.util.Arrays;
36import java.util.List;
37
Jason Monkd9edfa942017-09-25 12:38:53 -040038
39/**
40 * A SliceItem is a single unit in the tree structure of a {@link Slice}.
41 *
42 * A SliceItem a piece of content and some hints about what that content
43 * means or how it should be displayed. The types of content can be:
Jason Monkd054fb32017-11-07 21:52:10 -050044 * <li>{@link #FORMAT_SLICE}</li>
45 * <li>{@link #FORMAT_TEXT}</li>
46 * <li>{@link #FORMAT_IMAGE}</li>
47 * <li>{@link #FORMAT_ACTION}</li>
Jason Monk740a6502017-12-10 13:49:59 -050048 * <li>{@link #FORMAT_INT}</li>
Jason Monkd054fb32017-11-07 21:52:10 -050049 * <li>{@link #FORMAT_TIMESTAMP}</li>
50 * <li>{@link #FORMAT_REMOTE_INPUT}</li>
Jason Monkfed72bf2017-12-08 18:19:32 -050051 * <li>{@link #FORMAT_BUNDLE}</li>
Jason Monkd9edfa942017-09-25 12:38:53 -040052 *
53 * The hints that a {@link SliceItem} are a set of strings which annotate
54 * the content. The hints that are guaranteed to be understood by the system
55 * are defined on {@link Slice}.
Jason Monkd9edfa942017-09-25 12:38:53 -040056 */
57public final class SliceItem implements Parcelable {
58
Jason Monkfed72bf2017-12-08 18:19:32 -050059 private static final String TAG = "SliceItem";
60
Jason Monkd9edfa942017-09-25 12:38:53 -040061 /**
62 * @hide
63 */
Jeff Sharkey5db9a912017-12-08 17:32:32 -070064 @StringDef(prefix = { "FORMAT_" }, value = {
65 FORMAT_SLICE,
66 FORMAT_TEXT,
67 FORMAT_IMAGE,
68 FORMAT_ACTION,
Jason Monk740a6502017-12-10 13:49:59 -050069 FORMAT_INT,
Jason Monk106387f2018-03-06 16:32:28 -050070 FORMAT_LONG,
Jeff Sharkey5db9a912017-12-08 17:32:32 -070071 FORMAT_REMOTE_INPUT,
Jason Monkfed72bf2017-12-08 18:19:32 -050072 FORMAT_BUNDLE,
Jeff Sharkey5db9a912017-12-08 17:32:32 -070073 })
74 @Retention(RetentionPolicy.SOURCE)
Jason Monkd9edfa942017-09-25 12:38:53 -040075 public @interface SliceType {}
76
77 /**
78 * A {@link SliceItem} that contains a {@link Slice}
79 */
Jason Monkd054fb32017-11-07 21:52:10 -050080 public static final String FORMAT_SLICE = "slice";
Jason Monkd9edfa942017-09-25 12:38:53 -040081 /**
82 * A {@link SliceItem} that contains a {@link CharSequence}
83 */
Jason Monkd054fb32017-11-07 21:52:10 -050084 public static final String FORMAT_TEXT = "text";
Jason Monkd9edfa942017-09-25 12:38:53 -040085 /**
86 * A {@link SliceItem} that contains an {@link Icon}
87 */
Jason Monkd054fb32017-11-07 21:52:10 -050088 public static final String FORMAT_IMAGE = "image";
Jason Monkd9edfa942017-09-25 12:38:53 -040089 /**
90 * A {@link SliceItem} that contains a {@link PendingIntent}
91 *
92 * Note: Actions contain 2 pieces of data, In addition to the pending intent, the
93 * item contains a {@link Slice} that the action applies to.
94 */
Jason Monkd054fb32017-11-07 21:52:10 -050095 public static final String FORMAT_ACTION = "action";
Jason Monkd9edfa942017-09-25 12:38:53 -040096 /**
Jason Monk740a6502017-12-10 13:49:59 -050097 * A {@link SliceItem} that contains an int.
98 */
99 public static final String FORMAT_INT = "int";
100 /**
Jason Monk106387f2018-03-06 16:32:28 -0500101 * A {@link SliceItem} that contains a long.
Jason Monkd9edfa942017-09-25 12:38:53 -0400102 */
Jason Monk106387f2018-03-06 16:32:28 -0500103 public static final String FORMAT_LONG = "long";
104 /**
105 * @deprecated TO BE REMOVED
106 */
107 @Deprecated
108 public static final String FORMAT_TIMESTAMP = FORMAT_LONG;
Jason Monkd9edfa942017-09-25 12:38:53 -0400109 /**
110 * A {@link SliceItem} that contains a {@link RemoteInput}.
111 */
Jason Monkd054fb32017-11-07 21:52:10 -0500112 public static final String FORMAT_REMOTE_INPUT = "input";
Jason Monkfed72bf2017-12-08 18:19:32 -0500113 /**
114 * A {@link SliceItem} that contains a {@link Bundle}.
115 */
116 public static final String FORMAT_BUNDLE = "bundle";
Jason Monkd9edfa942017-09-25 12:38:53 -0400117
118 /**
119 * @hide
120 */
Jason Monkd18651f2017-10-05 14:18:49 -0400121 protected @Slice.SliceHint
122 String[] mHints;
Jason Monkd054fb32017-11-07 21:52:10 -0500123 private final String mFormat;
124 private final String mSubType;
Jason Monkd9edfa942017-09-25 12:38:53 -0400125 private final Object mObj;
126
127 /**
128 * @hide
129 */
Jason Monkd054fb32017-11-07 21:52:10 -0500130 public SliceItem(Object obj, @SliceType String format, String subType,
Jason Monk106387f2018-03-06 16:32:28 -0500131 List<String> hints) {
132 this(obj, format, subType, hints.toArray(new String[hints.size()]));
133 }
134
135 /**
136 * @hide
137 */
138 public SliceItem(Object obj, @SliceType String format, String subType,
Jason Monkd054fb32017-11-07 21:52:10 -0500139 @Slice.SliceHint String[] hints) {
Jason Monkd9edfa942017-09-25 12:38:53 -0400140 mHints = hints;
Jason Monkd054fb32017-11-07 21:52:10 -0500141 mFormat = format;
142 mSubType = subType;
Jason Monkd9edfa942017-09-25 12:38:53 -0400143 mObj = obj;
144 }
145
146 /**
147 * @hide
148 */
Jason Monkd054fb32017-11-07 21:52:10 -0500149 public SliceItem(PendingIntent intent, Slice slice, String format, String subType,
150 @Slice.SliceHint String[] hints) {
151 this(new Pair<>(intent, slice), format, subType, hints);
Jason Monkd9edfa942017-09-25 12:38:53 -0400152 }
153
154 /**
155 * Gets all hints associated with this SliceItem.
156 * @return Array of hints.
157 */
Jason Monkd18651f2017-10-05 14:18:49 -0400158 public @NonNull @Slice.SliceHint List<String> getHints() {
159 return Arrays.asList(mHints);
Jason Monkd9edfa942017-09-25 12:38:53 -0400160 }
161
162 /**
Jason Monkd054fb32017-11-07 21:52:10 -0500163 * Get the format of this SliceItem.
164 * <p>
165 * The format will be one of the following types supported by the platform:
166 * <li>{@link #FORMAT_SLICE}</li>
167 * <li>{@link #FORMAT_TEXT}</li>
168 * <li>{@link #FORMAT_IMAGE}</li>
169 * <li>{@link #FORMAT_ACTION}</li>
Jason Monk740a6502017-12-10 13:49:59 -0500170 * <li>{@link #FORMAT_INT}</li>
Jason Monkd054fb32017-11-07 21:52:10 -0500171 * <li>{@link #FORMAT_TIMESTAMP}</li>
172 * <li>{@link #FORMAT_REMOTE_INPUT}</li>
Jason Monkfed72bf2017-12-08 18:19:32 -0500173 * <li>{@link #FORMAT_BUNDLE}</li>
Jason Monkd054fb32017-11-07 21:52:10 -0500174 * @see #getSubType() ()
175 */
176 public String getFormat() {
177 return mFormat;
Jason Monkd9edfa942017-09-25 12:38:53 -0400178 }
179
180 /**
Jason Monkd054fb32017-11-07 21:52:10 -0500181 * Get the sub-type of this SliceItem.
182 * <p>
183 * Subtypes provide additional information about the type of this information beyond basic
184 * interpretations inferred by {@link #getFormat()}. For example a slice may contain
185 * many {@link #FORMAT_TEXT} items, but only some of them may be {@link Slice#SUBTYPE_MESSAGE}.
186 * @see #getFormat()
187 */
188 public String getSubType() {
189 return mSubType;
190 }
191
192 /**
193 * @return The text held by this {@link #FORMAT_TEXT} SliceItem
Jason Monkd9edfa942017-09-25 12:38:53 -0400194 */
195 public CharSequence getText() {
196 return (CharSequence) mObj;
197 }
198
199 /**
Jason Monkfed72bf2017-12-08 18:19:32 -0500200 * @return The parcelable held by this {@link #FORMAT_BUNDLE} SliceItem
201 */
202 public Bundle getBundle() {
203 return (Bundle) mObj;
204 }
205
206 /**
Jason Monkd054fb32017-11-07 21:52:10 -0500207 * @return The icon held by this {@link #FORMAT_IMAGE} SliceItem
Jason Monkd9edfa942017-09-25 12:38:53 -0400208 */
209 public Icon getIcon() {
210 return (Icon) mObj;
211 }
212
213 /**
Jason Monkd054fb32017-11-07 21:52:10 -0500214 * @return The pending intent held by this {@link #FORMAT_ACTION} SliceItem
Jason Monkd9edfa942017-09-25 12:38:53 -0400215 */
216 public PendingIntent getAction() {
217 return ((Pair<PendingIntent, Slice>) mObj).first;
218 }
219
220 /**
221 * @hide This isn't final
222 */
223 public RemoteViews getRemoteView() {
224 return (RemoteViews) mObj;
225 }
226
227 /**
Jason Monkd054fb32017-11-07 21:52:10 -0500228 * @return The remote input held by this {@link #FORMAT_REMOTE_INPUT} SliceItem
Jason Monkd9edfa942017-09-25 12:38:53 -0400229 */
230 public RemoteInput getRemoteInput() {
231 return (RemoteInput) mObj;
232 }
233
234 /**
Jason Monk740a6502017-12-10 13:49:59 -0500235 * @return The color held by this {@link #FORMAT_INT} SliceItem
236 */
237 public int getInt() {
238 return (Integer) mObj;
239 }
240
241 /**
Jason Monkd054fb32017-11-07 21:52:10 -0500242 * @return The slice held by this {@link #FORMAT_ACTION} or {@link #FORMAT_SLICE} SliceItem
Jason Monkd9edfa942017-09-25 12:38:53 -0400243 */
244 public Slice getSlice() {
Jason Monkc10e0e22017-11-28 14:53:04 -0500245 if (FORMAT_ACTION.equals(getFormat())) {
Jason Monkd9edfa942017-09-25 12:38:53 -0400246 return ((Pair<PendingIntent, Slice>) mObj).second;
247 }
248 return (Slice) mObj;
249 }
250
251 /**
Jason Monkd054fb32017-11-07 21:52:10 -0500252 * @return The timestamp held by this {@link #FORMAT_TIMESTAMP} SliceItem
Jason Monkd9edfa942017-09-25 12:38:53 -0400253 */
254 public long getTimestamp() {
255 return (Long) mObj;
256 }
257
258 /**
259 * @param hint The hint to check for
260 * @return true if this item contains the given hint
261 */
Jason Monkd18651f2017-10-05 14:18:49 -0400262 public boolean hasHint(@Slice.SliceHint String hint) {
Jason Monkd9edfa942017-09-25 12:38:53 -0400263 return ArrayUtils.contains(mHints, hint);
264 }
265
266 /**
267 * @hide
268 */
269 public SliceItem(Parcel in) {
270 mHints = in.readStringArray();
Jason Monkd054fb32017-11-07 21:52:10 -0500271 mFormat = in.readString();
272 mSubType = in.readString();
273 mObj = readObj(mFormat, in);
Jason Monkd9edfa942017-09-25 12:38:53 -0400274 }
275
276 @Override
277 public int describeContents() {
278 return 0;
279 }
280
281 @Override
282 public void writeToParcel(Parcel dest, int flags) {
283 dest.writeStringArray(mHints);
Jason Monkd054fb32017-11-07 21:52:10 -0500284 dest.writeString(mFormat);
285 dest.writeString(mSubType);
286 writeObj(dest, flags, mObj, mFormat);
Jason Monkd9edfa942017-09-25 12:38:53 -0400287 }
288
289 /**
290 * @hide
291 */
Jason Monkd18651f2017-10-05 14:18:49 -0400292 public boolean hasHints(@Slice.SliceHint String[] hints) {
Jason Monkd9edfa942017-09-25 12:38:53 -0400293 if (hints == null) return true;
294 for (String hint : hints) {
Mady Mellor4575aa52017-09-29 09:49:59 -0700295 if (!TextUtils.isEmpty(hint) && !ArrayUtils.contains(mHints, hint)) {
Jason Monkd9edfa942017-09-25 12:38:53 -0400296 return false;
297 }
298 }
299 return true;
300 }
301
302 /**
303 * @hide
304 */
Jason Monkd18651f2017-10-05 14:18:49 -0400305 public boolean hasAnyHints(@Slice.SliceHint String[] hints) {
Mady Mellor4575aa52017-09-29 09:49:59 -0700306 if (hints == null) return false;
Jason Monkd9edfa942017-09-25 12:38:53 -0400307 for (String hint : hints) {
308 if (ArrayUtils.contains(mHints, hint)) {
309 return true;
310 }
311 }
312 return false;
313 }
314
Jason Monkd054fb32017-11-07 21:52:10 -0500315 private static String getBaseType(String type) {
316 int index = type.indexOf('/');
317 if (index >= 0) {
318 return type.substring(0, index);
319 }
320 return type;
321 }
322
323 private static void writeObj(Parcel dest, int flags, Object obj, String type) {
324 switch (getBaseType(type)) {
325 case FORMAT_SLICE:
326 case FORMAT_IMAGE:
327 case FORMAT_REMOTE_INPUT:
Jason Monkfed72bf2017-12-08 18:19:32 -0500328 case FORMAT_BUNDLE:
Jason Monkd9edfa942017-09-25 12:38:53 -0400329 ((Parcelable) obj).writeToParcel(dest, flags);
330 break;
Jason Monkd054fb32017-11-07 21:52:10 -0500331 case FORMAT_ACTION:
Jason Monkd9edfa942017-09-25 12:38:53 -0400332 ((Pair<PendingIntent, Slice>) obj).first.writeToParcel(dest, flags);
333 ((Pair<PendingIntent, Slice>) obj).second.writeToParcel(dest, flags);
334 break;
Jason Monkd054fb32017-11-07 21:52:10 -0500335 case FORMAT_TEXT:
336 TextUtils.writeToParcel((CharSequence) obj, dest, flags);
Jason Monkd9edfa942017-09-25 12:38:53 -0400337 break;
Jason Monk740a6502017-12-10 13:49:59 -0500338 case FORMAT_INT:
Jason Monkd054fb32017-11-07 21:52:10 -0500339 dest.writeInt((Integer) obj);
Jason Monkd9edfa942017-09-25 12:38:53 -0400340 break;
Jason Monkd054fb32017-11-07 21:52:10 -0500341 case FORMAT_TIMESTAMP:
342 dest.writeLong((Long) obj);
Jason Monkd9edfa942017-09-25 12:38:53 -0400343 break;
344 }
345 }
346
Jason Monkd054fb32017-11-07 21:52:10 -0500347 private static Object readObj(String type, Parcel in) {
348 switch (getBaseType(type)) {
349 case FORMAT_SLICE:
Jason Monkd9edfa942017-09-25 12:38:53 -0400350 return Slice.CREATOR.createFromParcel(in);
Jason Monkd054fb32017-11-07 21:52:10 -0500351 case FORMAT_TEXT:
Jason Monkd9edfa942017-09-25 12:38:53 -0400352 return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
Jason Monkd054fb32017-11-07 21:52:10 -0500353 case FORMAT_IMAGE:
Jason Monkd9edfa942017-09-25 12:38:53 -0400354 return Icon.CREATOR.createFromParcel(in);
Jason Monkd054fb32017-11-07 21:52:10 -0500355 case FORMAT_ACTION:
356 return new Pair<>(
Jason Monkd9edfa942017-09-25 12:38:53 -0400357 PendingIntent.CREATOR.createFromParcel(in),
358 Slice.CREATOR.createFromParcel(in));
Jason Monk740a6502017-12-10 13:49:59 -0500359 case FORMAT_INT:
Jason Monkd9edfa942017-09-25 12:38:53 -0400360 return in.readInt();
Jason Monkd054fb32017-11-07 21:52:10 -0500361 case FORMAT_TIMESTAMP:
Jason Monkd9edfa942017-09-25 12:38:53 -0400362 return in.readLong();
Jason Monkd054fb32017-11-07 21:52:10 -0500363 case FORMAT_REMOTE_INPUT:
Jason Monkd9edfa942017-09-25 12:38:53 -0400364 return RemoteInput.CREATOR.createFromParcel(in);
Jason Monkfed72bf2017-12-08 18:19:32 -0500365 case FORMAT_BUNDLE:
366 return Bundle.CREATOR.createFromParcel(in);
Jason Monkd9edfa942017-09-25 12:38:53 -0400367 }
368 throw new RuntimeException("Unsupported type " + type);
369 }
370
371 public static final Creator<SliceItem> CREATOR = new Creator<SliceItem>() {
372 @Override
373 public SliceItem createFromParcel(Parcel in) {
374 return new SliceItem(in);
375 }
376
377 @Override
378 public SliceItem[] newArray(int size) {
379 return new SliceItem[size];
380 }
381 };
Jason Monkd9edfa942017-09-25 12:38:53 -0400382}