blob: ed32a1b7be2c49cc20b118295a5712c625cccc2f [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>
Jeff Sharkey3990ee12018-04-11 10:19:55 -060049 * <li>{@link #FORMAT_LONG}</li>
Jason Monkd054fb32017-11-07 21:52:10 -050050 * <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
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600106 * @removed
Jason Monk106387f2018-03-06 16:32:28 -0500107 */
108 @Deprecated
109 public static final String FORMAT_TIMESTAMP = FORMAT_LONG;
Jason Monkd9edfa942017-09-25 12:38:53 -0400110 /**
111 * A {@link SliceItem} that contains a {@link RemoteInput}.
112 */
Jason Monkd054fb32017-11-07 21:52:10 -0500113 public static final String FORMAT_REMOTE_INPUT = "input";
Jason Monkfed72bf2017-12-08 18:19:32 -0500114 /**
115 * A {@link SliceItem} that contains a {@link Bundle}.
116 */
117 public static final String FORMAT_BUNDLE = "bundle";
Jason Monkd9edfa942017-09-25 12:38:53 -0400118
119 /**
120 * @hide
121 */
Jason Monkd18651f2017-10-05 14:18:49 -0400122 protected @Slice.SliceHint
123 String[] mHints;
Jason Monkd054fb32017-11-07 21:52:10 -0500124 private final String mFormat;
125 private final String mSubType;
Jason Monkd9edfa942017-09-25 12:38:53 -0400126 private final Object mObj;
127
128 /**
129 * @hide
130 */
Jason Monkd054fb32017-11-07 21:52:10 -0500131 public SliceItem(Object obj, @SliceType String format, String subType,
Jason Monk106387f2018-03-06 16:32:28 -0500132 List<String> hints) {
133 this(obj, format, subType, hints.toArray(new String[hints.size()]));
134 }
135
136 /**
137 * @hide
138 */
139 public SliceItem(Object obj, @SliceType String format, String subType,
Jason Monkd054fb32017-11-07 21:52:10 -0500140 @Slice.SliceHint String[] hints) {
Jason Monkd9edfa942017-09-25 12:38:53 -0400141 mHints = hints;
Jason Monkd054fb32017-11-07 21:52:10 -0500142 mFormat = format;
143 mSubType = subType;
Jason Monkd9edfa942017-09-25 12:38:53 -0400144 mObj = obj;
145 }
146
147 /**
148 * @hide
149 */
Jason Monkd054fb32017-11-07 21:52:10 -0500150 public SliceItem(PendingIntent intent, Slice slice, String format, String subType,
151 @Slice.SliceHint String[] hints) {
152 this(new Pair<>(intent, slice), format, subType, hints);
Jason Monkd9edfa942017-09-25 12:38:53 -0400153 }
154
155 /**
156 * Gets all hints associated with this SliceItem.
157 * @return Array of hints.
158 */
Jason Monkd18651f2017-10-05 14:18:49 -0400159 public @NonNull @Slice.SliceHint List<String> getHints() {
160 return Arrays.asList(mHints);
Jason Monkd9edfa942017-09-25 12:38:53 -0400161 }
162
163 /**
Jason Monkd054fb32017-11-07 21:52:10 -0500164 * Get the format of this SliceItem.
165 * <p>
166 * The format will be one of the following types supported by the platform:
167 * <li>{@link #FORMAT_SLICE}</li>
168 * <li>{@link #FORMAT_TEXT}</li>
169 * <li>{@link #FORMAT_IMAGE}</li>
170 * <li>{@link #FORMAT_ACTION}</li>
Jason Monk740a6502017-12-10 13:49:59 -0500171 * <li>{@link #FORMAT_INT}</li>
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600172 * <li>{@link #FORMAT_LONG}</li>
Jason Monkd054fb32017-11-07 21:52:10 -0500173 * <li>{@link #FORMAT_REMOTE_INPUT}</li>
Jason Monkfed72bf2017-12-08 18:19:32 -0500174 * <li>{@link #FORMAT_BUNDLE}</li>
Jason Monkd054fb32017-11-07 21:52:10 -0500175 * @see #getSubType() ()
176 */
177 public String getFormat() {
178 return mFormat;
Jason Monkd9edfa942017-09-25 12:38:53 -0400179 }
180
181 /**
Jason Monkd054fb32017-11-07 21:52:10 -0500182 * Get the sub-type of this SliceItem.
183 * <p>
184 * Subtypes provide additional information about the type of this information beyond basic
185 * interpretations inferred by {@link #getFormat()}. For example a slice may contain
186 * many {@link #FORMAT_TEXT} items, but only some of them may be {@link Slice#SUBTYPE_MESSAGE}.
187 * @see #getFormat()
188 */
189 public String getSubType() {
190 return mSubType;
191 }
192
193 /**
194 * @return The text held by this {@link #FORMAT_TEXT} SliceItem
Jason Monkd9edfa942017-09-25 12:38:53 -0400195 */
196 public CharSequence getText() {
197 return (CharSequence) mObj;
198 }
199
200 /**
Jason Monkfed72bf2017-12-08 18:19:32 -0500201 * @return The parcelable held by this {@link #FORMAT_BUNDLE} SliceItem
202 */
203 public Bundle getBundle() {
204 return (Bundle) mObj;
205 }
206
207 /**
Jason Monkd054fb32017-11-07 21:52:10 -0500208 * @return The icon held by this {@link #FORMAT_IMAGE} SliceItem
Jason Monkd9edfa942017-09-25 12:38:53 -0400209 */
210 public Icon getIcon() {
211 return (Icon) mObj;
212 }
213
214 /**
Jason Monkd054fb32017-11-07 21:52:10 -0500215 * @return The pending intent held by this {@link #FORMAT_ACTION} SliceItem
Jason Monkd9edfa942017-09-25 12:38:53 -0400216 */
217 public PendingIntent getAction() {
218 return ((Pair<PendingIntent, Slice>) mObj).first;
219 }
220
221 /**
222 * @hide This isn't final
223 */
224 public RemoteViews getRemoteView() {
225 return (RemoteViews) mObj;
226 }
227
228 /**
Jason Monkd054fb32017-11-07 21:52:10 -0500229 * @return The remote input held by this {@link #FORMAT_REMOTE_INPUT} SliceItem
Jason Monkd9edfa942017-09-25 12:38:53 -0400230 */
231 public RemoteInput getRemoteInput() {
232 return (RemoteInput) mObj;
233 }
234
235 /**
Jason Monk740a6502017-12-10 13:49:59 -0500236 * @return The color held by this {@link #FORMAT_INT} SliceItem
237 */
238 public int getInt() {
239 return (Integer) mObj;
240 }
241
242 /**
Jason Monkd054fb32017-11-07 21:52:10 -0500243 * @return The slice held by this {@link #FORMAT_ACTION} or {@link #FORMAT_SLICE} SliceItem
Jason Monkd9edfa942017-09-25 12:38:53 -0400244 */
245 public Slice getSlice() {
Jason Monkc10e0e22017-11-28 14:53:04 -0500246 if (FORMAT_ACTION.equals(getFormat())) {
Jason Monkd9edfa942017-09-25 12:38:53 -0400247 return ((Pair<PendingIntent, Slice>) mObj).second;
248 }
249 return (Slice) mObj;
250 }
251
252 /**
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600253 * @return The long held by this {@link #FORMAT_LONG} SliceItem
Jason Monkd9edfa942017-09-25 12:38:53 -0400254 */
Jeff Sharkey3990ee12018-04-11 10:19:55 -0600255 public long getLong() {
256 return (Long) mObj;
257 }
258
259 /**
260 * @deprecated replaced by {@link #getLong()}
261 * @removed
262 */
263 @Deprecated
Jason Monkd9edfa942017-09-25 12:38:53 -0400264 public long getTimestamp() {
265 return (Long) mObj;
266 }
267
268 /**
269 * @param hint The hint to check for
270 * @return true if this item contains the given hint
271 */
Jason Monkd18651f2017-10-05 14:18:49 -0400272 public boolean hasHint(@Slice.SliceHint String hint) {
Jason Monkd9edfa942017-09-25 12:38:53 -0400273 return ArrayUtils.contains(mHints, hint);
274 }
275
276 /**
277 * @hide
278 */
279 public SliceItem(Parcel in) {
280 mHints = in.readStringArray();
Jason Monkd054fb32017-11-07 21:52:10 -0500281 mFormat = in.readString();
282 mSubType = in.readString();
283 mObj = readObj(mFormat, in);
Jason Monkd9edfa942017-09-25 12:38:53 -0400284 }
285
286 @Override
287 public int describeContents() {
288 return 0;
289 }
290
291 @Override
292 public void writeToParcel(Parcel dest, int flags) {
293 dest.writeStringArray(mHints);
Jason Monkd054fb32017-11-07 21:52:10 -0500294 dest.writeString(mFormat);
295 dest.writeString(mSubType);
296 writeObj(dest, flags, mObj, mFormat);
Jason Monkd9edfa942017-09-25 12:38:53 -0400297 }
298
299 /**
300 * @hide
301 */
Jason Monkd18651f2017-10-05 14:18:49 -0400302 public boolean hasHints(@Slice.SliceHint String[] hints) {
Jason Monkd9edfa942017-09-25 12:38:53 -0400303 if (hints == null) return true;
304 for (String hint : hints) {
Mady Mellor4575aa52017-09-29 09:49:59 -0700305 if (!TextUtils.isEmpty(hint) && !ArrayUtils.contains(mHints, hint)) {
Jason Monkd9edfa942017-09-25 12:38:53 -0400306 return false;
307 }
308 }
309 return true;
310 }
311
312 /**
313 * @hide
314 */
Jason Monkd18651f2017-10-05 14:18:49 -0400315 public boolean hasAnyHints(@Slice.SliceHint String[] hints) {
Mady Mellor4575aa52017-09-29 09:49:59 -0700316 if (hints == null) return false;
Jason Monkd9edfa942017-09-25 12:38:53 -0400317 for (String hint : hints) {
318 if (ArrayUtils.contains(mHints, hint)) {
319 return true;
320 }
321 }
322 return false;
323 }
324
Jason Monkd054fb32017-11-07 21:52:10 -0500325 private static String getBaseType(String type) {
326 int index = type.indexOf('/');
327 if (index >= 0) {
328 return type.substring(0, index);
329 }
330 return type;
331 }
332
333 private static void writeObj(Parcel dest, int flags, Object obj, String type) {
334 switch (getBaseType(type)) {
335 case FORMAT_SLICE:
336 case FORMAT_IMAGE:
337 case FORMAT_REMOTE_INPUT:
Jason Monkfed72bf2017-12-08 18:19:32 -0500338 case FORMAT_BUNDLE:
Jason Monkd9edfa942017-09-25 12:38:53 -0400339 ((Parcelable) obj).writeToParcel(dest, flags);
340 break;
Jason Monkd054fb32017-11-07 21:52:10 -0500341 case FORMAT_ACTION:
Jason Monkd9edfa942017-09-25 12:38:53 -0400342 ((Pair<PendingIntent, Slice>) obj).first.writeToParcel(dest, flags);
343 ((Pair<PendingIntent, Slice>) obj).second.writeToParcel(dest, flags);
344 break;
Jason Monkd054fb32017-11-07 21:52:10 -0500345 case FORMAT_TEXT:
346 TextUtils.writeToParcel((CharSequence) obj, dest, flags);
Jason Monkd9edfa942017-09-25 12:38:53 -0400347 break;
Jason Monk740a6502017-12-10 13:49:59 -0500348 case FORMAT_INT:
Jason Monkd054fb32017-11-07 21:52:10 -0500349 dest.writeInt((Integer) obj);
Jason Monkd9edfa942017-09-25 12:38:53 -0400350 break;
Jason Monkd054fb32017-11-07 21:52:10 -0500351 case FORMAT_TIMESTAMP:
352 dest.writeLong((Long) obj);
Jason Monkd9edfa942017-09-25 12:38:53 -0400353 break;
354 }
355 }
356
Jason Monkd054fb32017-11-07 21:52:10 -0500357 private static Object readObj(String type, Parcel in) {
358 switch (getBaseType(type)) {
359 case FORMAT_SLICE:
Jason Monkd9edfa942017-09-25 12:38:53 -0400360 return Slice.CREATOR.createFromParcel(in);
Jason Monkd054fb32017-11-07 21:52:10 -0500361 case FORMAT_TEXT:
Jason Monkd9edfa942017-09-25 12:38:53 -0400362 return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
Jason Monkd054fb32017-11-07 21:52:10 -0500363 case FORMAT_IMAGE:
Jason Monkd9edfa942017-09-25 12:38:53 -0400364 return Icon.CREATOR.createFromParcel(in);
Jason Monkd054fb32017-11-07 21:52:10 -0500365 case FORMAT_ACTION:
366 return new Pair<>(
Jason Monkd9edfa942017-09-25 12:38:53 -0400367 PendingIntent.CREATOR.createFromParcel(in),
368 Slice.CREATOR.createFromParcel(in));
Jason Monk740a6502017-12-10 13:49:59 -0500369 case FORMAT_INT:
Jason Monkd9edfa942017-09-25 12:38:53 -0400370 return in.readInt();
Jason Monkd054fb32017-11-07 21:52:10 -0500371 case FORMAT_TIMESTAMP:
Jason Monkd9edfa942017-09-25 12:38:53 -0400372 return in.readLong();
Jason Monkd054fb32017-11-07 21:52:10 -0500373 case FORMAT_REMOTE_INPUT:
Jason Monkd9edfa942017-09-25 12:38:53 -0400374 return RemoteInput.CREATOR.createFromParcel(in);
Jason Monkfed72bf2017-12-08 18:19:32 -0500375 case FORMAT_BUNDLE:
376 return Bundle.CREATOR.createFromParcel(in);
Jason Monkd9edfa942017-09-25 12:38:53 -0400377 }
378 throw new RuntimeException("Unsupported type " + type);
379 }
380
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700381 public static final @android.annotation.NonNull Creator<SliceItem> CREATOR = new Creator<SliceItem>() {
Jason Monkd9edfa942017-09-25 12:38:53 -0400382 @Override
383 public SliceItem createFromParcel(Parcel in) {
384 return new SliceItem(in);
385 }
386
387 @Override
388 public SliceItem[] newArray(int size) {
389 return new SliceItem[size];
390 }
391 };
Jason Monkd9edfa942017-09-25 12:38:53 -0400392}