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 17 package android.app.slice; 18 19 import android.annotation.NonNull; 20 import android.annotation.StringDef; 21 import android.app.PendingIntent; 22 import android.app.RemoteInput; 23 import android.graphics.drawable.Icon; 24 import android.os.Bundle; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 import android.text.TextUtils; 28 import android.util.Pair; 29 import android.widget.RemoteViews; 30 31 import com.android.internal.util.ArrayUtils; 32 33 import java.lang.annotation.Retention; 34 import java.lang.annotation.RetentionPolicy; 35 import java.util.Arrays; 36 import 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_LONG}</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 * @deprecated Slice framework has been deprecated, it will not receive any updates from 57 * {@link android.os.Build.VANILLA_ICE_CREAM} and forward. If you are looking for a 58 * framework that sends displayable data from one app to another, consider using 59 * {@link android.app.appsearch.AppSearchManager}. 60 */ 61 @Deprecated 62 public final class SliceItem implements Parcelable { 63 64 private static final String TAG = "SliceItem"; 65 66 /** 67 * @hide 68 */ 69 @StringDef(prefix = { "FORMAT_" }, value = { 70 FORMAT_SLICE, 71 FORMAT_TEXT, 72 FORMAT_IMAGE, 73 FORMAT_ACTION, 74 FORMAT_INT, 75 FORMAT_LONG, 76 FORMAT_REMOTE_INPUT, 77 FORMAT_BUNDLE, 78 }) 79 @Retention(RetentionPolicy.SOURCE) 80 public @interface SliceType {} 81 82 /** 83 * A {@link SliceItem} that contains a {@link Slice} 84 */ 85 public static final String FORMAT_SLICE = "slice"; 86 /** 87 * A {@link SliceItem} that contains a {@link CharSequence} 88 */ 89 public static final String FORMAT_TEXT = "text"; 90 /** 91 * A {@link SliceItem} that contains an {@link Icon} 92 */ 93 public static final String FORMAT_IMAGE = "image"; 94 /** 95 * A {@link SliceItem} that contains a {@link PendingIntent} 96 * 97 * Note: Actions contain 2 pieces of data, In addition to the pending intent, the 98 * item contains a {@link Slice} that the action applies to. 99 */ 100 public static final String FORMAT_ACTION = "action"; 101 /** 102 * A {@link SliceItem} that contains an int. 103 */ 104 public static final String FORMAT_INT = "int"; 105 /** 106 * A {@link SliceItem} that contains a long. 107 */ 108 public static final String FORMAT_LONG = "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 */ SliceItem(Object obj, @SliceType String format, String subType, List<String> hints)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 */ SliceItem(Object obj, @SliceType String format, String subType, @Slice.SliceHint String[] hints)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 */ SliceItem(PendingIntent intent, Slice slice, String format, String subType, @Slice.SliceHint String[] hints)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 */ getHints()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_LONG}</li> 172 * <li>{@link #FORMAT_REMOTE_INPUT}</li> 173 * <li>{@link #FORMAT_BUNDLE}</li> 174 * @see #getSubType() () 175 */ getFormat()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 */ getSubType()188 public String getSubType() { 189 return mSubType; 190 } 191 192 /** 193 * @return The text held by this {@link #FORMAT_TEXT} SliceItem 194 */ getText()195 public CharSequence getText() { 196 return (CharSequence) mObj; 197 } 198 199 /** 200 * @return The parcelable held by this {@link #FORMAT_BUNDLE} SliceItem 201 */ getBundle()202 public Bundle getBundle() { 203 return (Bundle) mObj; 204 } 205 206 /** 207 * @return The icon held by this {@link #FORMAT_IMAGE} SliceItem 208 */ getIcon()209 public Icon getIcon() { 210 return (Icon) mObj; 211 } 212 213 /** 214 * @return The pending intent held by this {@link #FORMAT_ACTION} SliceItem 215 */ getAction()216 public PendingIntent getAction() { 217 return ((Pair<PendingIntent, Slice>) mObj).first; 218 } 219 220 /** 221 * @hide This isn't final 222 */ getRemoteView()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 */ getRemoteInput()230 public RemoteInput getRemoteInput() { 231 return (RemoteInput) mObj; 232 } 233 234 /** 235 * @return The color held by this {@link #FORMAT_INT} SliceItem 236 */ getInt()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 */ getSlice()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 long held by this {@link #FORMAT_LONG} SliceItem 253 */ getLong()254 public long getLong() { 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 */ hasHint(@lice.SliceHint String hint)262 public boolean hasHint(@Slice.SliceHint String hint) { 263 return ArrayUtils.contains(mHints, hint); 264 } 265 266 /** 267 * @hide 268 */ SliceItem(Parcel in)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 describeContents()277 public int describeContents() { 278 return 0; 279 } 280 281 @Override writeToParcel(Parcel dest, int flags)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 */ hasHints(@lice.SliceHint String[] hints)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 */ hasAnyHints(@lice.SliceHint String[] hints)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 getBaseType(String type)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 writeObj(Parcel dest, int flags, Object obj, String type)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_LONG: 342 dest.writeLong((Long) obj); 343 break; 344 } 345 } 346 readObj(String type, Parcel in)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_LONG: 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 @android.annotation.NonNull 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