SliceItem.java revision 106387f0b283beeb5318f05e2033f15798e274b3
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 17package android.app.slice; 18 19import android.annotation.NonNull; 20import android.annotation.StringDef; 21import android.app.PendingIntent; 22import android.app.RemoteInput; 23import android.graphics.drawable.Icon; 24import android.os.Bundle; 25import android.os.Parcel; 26import android.os.Parcelable; 27import android.text.TextUtils; 28import android.util.Pair; 29import android.widget.RemoteViews; 30 31import com.android.internal.util.ArrayUtils; 32 33import java.lang.annotation.Retention; 34import java.lang.annotation.RetentionPolicy; 35import java.util.Arrays; 36import java.util.List; 37 38 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: 44 * <li>{@link #FORMAT_SLICE}</li> 45 * <li>{@link #FORMAT_TEXT}</li> 46 * <li>{@link #FORMAT_IMAGE}</li> 47 * <li>{@link #FORMAT_ACTION}</li> 48 * <li>{@link #FORMAT_INT}</li> 49 * <li>{@link #FORMAT_TIMESTAMP}</li> 50 * <li>{@link #FORMAT_REMOTE_INPUT}</li> 51 * <li>{@link #FORMAT_BUNDLE}</li> 52 * 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}. 56 */ 57public final class SliceItem implements Parcelable { 58 59 private static final String TAG = "SliceItem"; 60 61 /** 62 * @hide 63 */ 64 @StringDef(prefix = { "FORMAT_" }, value = { 65 FORMAT_SLICE, 66 FORMAT_TEXT, 67 FORMAT_IMAGE, 68 FORMAT_ACTION, 69 FORMAT_INT, 70 FORMAT_LONG, 71 FORMAT_REMOTE_INPUT, 72 FORMAT_BUNDLE, 73 }) 74 @Retention(RetentionPolicy.SOURCE) 75 public @interface SliceType {} 76 77 /** 78 * A {@link SliceItem} that contains a {@link Slice} 79 */ 80 public static final String FORMAT_SLICE = "slice"; 81 /** 82 * A {@link SliceItem} that contains a {@link CharSequence} 83 */ 84 public static final String FORMAT_TEXT = "text"; 85 /** 86 * A {@link SliceItem} that contains an {@link Icon} 87 */ 88 public static final String FORMAT_IMAGE = "image"; 89 /** 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 */ 95 public static final String FORMAT_ACTION = "action"; 96 /** 97 * A {@link SliceItem} that contains an int. 98 */ 99 public static final String FORMAT_INT = "int"; 100 /** 101 * A {@link SliceItem} that contains a long. 102 */ 103 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; 109 /** 110 * A {@link SliceItem} that contains a {@link RemoteInput}. 111 */ 112 public static final String FORMAT_REMOTE_INPUT = "input"; 113 /** 114 * A {@link SliceItem} that contains a {@link Bundle}. 115 */ 116 public static final String FORMAT_BUNDLE = "bundle"; 117 118 /** 119 * @hide 120 */ 121 protected @Slice.SliceHint 122 String[] mHints; 123 private final String mFormat; 124 private final String mSubType; 125 private final Object mObj; 126 127 /** 128 * @hide 129 */ 130 public SliceItem(Object obj, @SliceType String format, String subType, 131 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, 139 @Slice.SliceHint String[] hints) { 140 mHints = hints; 141 mFormat = format; 142 mSubType = subType; 143 mObj = obj; 144 } 145 146 /** 147 * @hide 148 */ 149 public SliceItem(PendingIntent intent, Slice slice, String format, String subType, 150 @Slice.SliceHint String[] hints) { 151 this(new Pair<>(intent, slice), format, subType, hints); 152 } 153 154 /** 155 * Gets all hints associated with this SliceItem. 156 * @return Array of hints. 157 */ 158 public @NonNull @Slice.SliceHint List<String> getHints() { 159 return Arrays.asList(mHints); 160 } 161 162 /** 163 * 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> 170 * <li>{@link #FORMAT_INT}</li> 171 * <li>{@link #FORMAT_TIMESTAMP}</li> 172 * <li>{@link #FORMAT_REMOTE_INPUT}</li> 173 * <li>{@link #FORMAT_BUNDLE}</li> 174 * @see #getSubType() () 175 */ 176 public String getFormat() { 177 return mFormat; 178 } 179 180 /** 181 * 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 194 */ 195 public CharSequence getText() { 196 return (CharSequence) mObj; 197 } 198 199 /** 200 * @return The parcelable held by this {@link #FORMAT_BUNDLE} SliceItem 201 */ 202 public Bundle getBundle() { 203 return (Bundle) mObj; 204 } 205 206 /** 207 * @return The icon held by this {@link #FORMAT_IMAGE} SliceItem 208 */ 209 public Icon getIcon() { 210 return (Icon) mObj; 211 } 212 213 /** 214 * @return The pending intent held by this {@link #FORMAT_ACTION} SliceItem 215 */ 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 /** 228 * @return The remote input held by this {@link #FORMAT_REMOTE_INPUT} SliceItem 229 */ 230 public RemoteInput getRemoteInput() { 231 return (RemoteInput) mObj; 232 } 233 234 /** 235 * @return The color held by this {@link #FORMAT_INT} SliceItem 236 */ 237 public int getInt() { 238 return (Integer) mObj; 239 } 240 241 /** 242 * @return The slice held by this {@link #FORMAT_ACTION} or {@link #FORMAT_SLICE} SliceItem 243 */ 244 public Slice getSlice() { 245 if (FORMAT_ACTION.equals(getFormat())) { 246 return ((Pair<PendingIntent, Slice>) mObj).second; 247 } 248 return (Slice) mObj; 249 } 250 251 /** 252 * @return The timestamp held by this {@link #FORMAT_TIMESTAMP} SliceItem 253 */ 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 */ 262 public boolean hasHint(@Slice.SliceHint String hint) { 263 return ArrayUtils.contains(mHints, hint); 264 } 265 266 /** 267 * @hide 268 */ 269 public SliceItem(Parcel in) { 270 mHints = in.readStringArray(); 271 mFormat = in.readString(); 272 mSubType = in.readString(); 273 mObj = readObj(mFormat, in); 274 } 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); 284 dest.writeString(mFormat); 285 dest.writeString(mSubType); 286 writeObj(dest, flags, mObj, mFormat); 287 } 288 289 /** 290 * @hide 291 */ 292 public boolean hasHints(@Slice.SliceHint String[] hints) { 293 if (hints == null) return true; 294 for (String hint : hints) { 295 if (!TextUtils.isEmpty(hint) && !ArrayUtils.contains(mHints, hint)) { 296 return false; 297 } 298 } 299 return true; 300 } 301 302 /** 303 * @hide 304 */ 305 public boolean hasAnyHints(@Slice.SliceHint String[] hints) { 306 if (hints == null) return false; 307 for (String hint : hints) { 308 if (ArrayUtils.contains(mHints, hint)) { 309 return true; 310 } 311 } 312 return false; 313 } 314 315 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: 328 case FORMAT_BUNDLE: 329 ((Parcelable) obj).writeToParcel(dest, flags); 330 break; 331 case FORMAT_ACTION: 332 ((Pair<PendingIntent, Slice>) obj).first.writeToParcel(dest, flags); 333 ((Pair<PendingIntent, Slice>) obj).second.writeToParcel(dest, flags); 334 break; 335 case FORMAT_TEXT: 336 TextUtils.writeToParcel((CharSequence) obj, dest, flags); 337 break; 338 case FORMAT_INT: 339 dest.writeInt((Integer) obj); 340 break; 341 case FORMAT_TIMESTAMP: 342 dest.writeLong((Long) obj); 343 break; 344 } 345 } 346 347 private static Object readObj(String type, Parcel in) { 348 switch (getBaseType(type)) { 349 case FORMAT_SLICE: 350 return Slice.CREATOR.createFromParcel(in); 351 case FORMAT_TEXT: 352 return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 353 case FORMAT_IMAGE: 354 return Icon.CREATOR.createFromParcel(in); 355 case FORMAT_ACTION: 356 return new Pair<>( 357 PendingIntent.CREATOR.createFromParcel(in), 358 Slice.CREATOR.createFromParcel(in)); 359 case FORMAT_INT: 360 return in.readInt(); 361 case FORMAT_TIMESTAMP: 362 return in.readLong(); 363 case FORMAT_REMOTE_INPUT: 364 return RemoteInput.CREATOR.createFromParcel(in); 365 case FORMAT_BUNDLE: 366 return Bundle.CREATOR.createFromParcel(in); 367 } 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 }; 382} 383