blob: e4412d1fabc74151797d318226ca8b2e425902c0 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.app.slice;
import static android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_COLOR;
import static android.app.slice.SliceItem.FORMAT_IMAGE;
import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
import static android.app.slice.SliceItem.FORMAT_SLICE;
import static android.app.slice.SliceItem.FORMAT_TEXT;
import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.annotation.RestrictTo;
import android.support.annotation.RestrictTo.Scope;
import android.support.annotation.StringDef;
import android.text.TextUtils;
import android.util.Pair;
import java.util.Arrays;
import java.util.List;
/**
* A SliceItem is a single unit in the tree structure of a {@link Slice}.
* <p>
* A SliceItem a piece of content and some hints about what that content
* means or how it should be displayed. The types of content can be:
* <li>{@link android.app.slice.SliceItem#FORMAT_SLICE}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_TEXT}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_IMAGE}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_ACTION}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_COLOR}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_TIMESTAMP}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_REMOTE_INPUT}</li>
* <p>
* The hints that a {@link SliceItem} are a set of strings which annotate
* the content. The hints that are guaranteed to be understood by the system
* are defined on {@link Slice}.
*/
public class SliceItem {
private static final String HINTS = "hints";
private static final String FORMAT = "format";
private static final String SUBTYPE = "subtype";
private static final String OBJ = "obj";
private static final String OBJ_2 = "obj_2";
/**
* @hide
*/
@RestrictTo(Scope.LIBRARY)
@StringDef({FORMAT_SLICE, FORMAT_TEXT, FORMAT_IMAGE, FORMAT_ACTION, FORMAT_COLOR,
FORMAT_TIMESTAMP, FORMAT_REMOTE_INPUT})
public @interface SliceType {
}
/**
* @hide
*/
@RestrictTo(Scope.LIBRARY)
protected @Slice.SliceHint String[] mHints;
private final String mFormat;
private final String mSubType;
private final Object mObj;
/**
* @hide
*/
@RestrictTo(Scope.LIBRARY)
public SliceItem(Object obj, @SliceType String format, String subType,
@Slice.SliceHint String[] hints) {
mHints = hints;
mFormat = format;
mSubType = subType;
mObj = obj;
}
/**
* @hide
*/
@RestrictTo(Scope.LIBRARY)
public SliceItem(PendingIntent intent, Slice slice, String format, String subType,
@Slice.SliceHint String[] hints) {
this(new Pair<>(intent, slice), format, subType, hints);
}
/**
* Gets all hints associated with this SliceItem.
*
* @return Array of hints.
*/
public @NonNull @Slice.SliceHint List<String> getHints() {
return Arrays.asList(mHints);
}
/**
* @hide
*/
@RestrictTo(Scope.LIBRARY)
public void addHint(@Slice.SliceHint String hint) {
mHints = ArrayUtils.appendElement(String.class, mHints, hint);
}
/**
* @hide
*/
@RestrictTo(Scope.LIBRARY)
public void removeHint(String hint) {
ArrayUtils.removeElement(String.class, mHints, hint);
}
/**
* Get the format of this SliceItem.
* <p>
* The format will be one of the following types supported by the platform:
* <li>{@link android.app.slice.SliceItem#FORMAT_SLICE}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_TEXT}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_IMAGE}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_ACTION}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_COLOR}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_TIMESTAMP}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_REMOTE_INPUT}</li>
* @see #getSubType() ()
*/
public @SliceType String getFormat() {
return mFormat;
}
/**
* Get the sub-type of this SliceItem.
* <p>
* Subtypes provide additional information about the type of this information beyond basic
* interpretations inferred by {@link #getFormat()}. For example a slice may contain
* many {@link android.app.slice.SliceItem#FORMAT_TEXT} items, but only some of them may be
* {@link android.app.slice.Slice#SUBTYPE_MESSAGE}.
* @see #getFormat()
*/
public String getSubType() {
return mSubType;
}
/**
* @return The text held by this {@link android.app.slice.SliceItem#FORMAT_TEXT} SliceItem
*/
public CharSequence getText() {
return (CharSequence) mObj;
}
/**
* @return The icon held by this {@link android.app.slice.SliceItem#FORMAT_IMAGE} SliceItem
*/
@RequiresApi(23)
public Icon getIcon() {
return (Icon) mObj;
}
/**
* @return The pending intent held by this {@link android.app.slice.SliceItem#FORMAT_ACTION}
* SliceItem
*/
public PendingIntent getAction() {
return ((Pair<PendingIntent, Slice>) mObj).first;
}
/**
* @return The remote input held by this {@link android.app.slice.SliceItem#FORMAT_REMOTE_INPUT}
* SliceItem
*/
@RequiresApi(20)
public RemoteInput getRemoteInput() {
return (RemoteInput) mObj;
}
/**
* @return The color held by this {@link android.app.slice.SliceItem#FORMAT_COLOR} SliceItem
*/
public int getColor() {
return (Integer) mObj;
}
/**
* @return The slice held by this {@link android.app.slice.SliceItem#FORMAT_ACTION} or
* {@link android.app.slice.SliceItem#FORMAT_SLICE} SliceItem
*/
public Slice getSlice() {
if (FORMAT_ACTION.equals(getFormat())) {
return ((Pair<PendingIntent, Slice>) mObj).second;
}
return (Slice) mObj;
}
/**
* @return The timestamp held by this {@link android.app.slice.SliceItem#FORMAT_TIMESTAMP}
* SliceItem
*/
public long getTimestamp() {
return (Long) mObj;
}
/**
* @param hint The hint to check for
* @return true if this item contains the given hint
*/
public boolean hasHint(@Slice.SliceHint String hint) {
return ArrayUtils.contains(mHints, hint);
}
/**
* @hide
*/
@RestrictTo(Scope.LIBRARY)
public SliceItem(Bundle in) {
mHints = in.getStringArray(HINTS);
mFormat = in.getString(FORMAT);
mSubType = in.getString(SUBTYPE);
mObj = readObj(mFormat, in);
}
/**
* @hide
* @return
*/
@RestrictTo(Scope.LIBRARY)
public Bundle toBundle() {
Bundle b = new Bundle();
b.putStringArray(HINTS, mHints);
b.putString(FORMAT, mFormat);
b.putString(SUBTYPE, mSubType);
writeObj(b, mObj, mFormat);
return b;
}
/**
* @hide
*/
@RestrictTo(Scope.LIBRARY)
public boolean hasHints(@Slice.SliceHint String[] hints) {
if (hints == null) return true;
for (String hint : hints) {
if (!TextUtils.isEmpty(hint) && !ArrayUtils.contains(mHints, hint)) {
return false;
}
}
return true;
}
/**
* @hide
*/
@RestrictTo(Scope.LIBRARY)
public boolean hasAnyHints(@Slice.SliceHint String[] hints) {
if (hints == null) return false;
for (String hint : hints) {
if (ArrayUtils.contains(mHints, hint)) {
return true;
}
}
return false;
}
private void writeObj(Bundle dest, Object obj, String type) {
switch (type) {
case FORMAT_IMAGE:
case FORMAT_REMOTE_INPUT:
dest.putParcelable(OBJ, (Parcelable) obj);
break;
case FORMAT_SLICE:
dest.putParcelable(OBJ, ((Slice) obj).toBundle());
break;
case FORMAT_ACTION:
dest.putParcelable(OBJ, ((Pair<PendingIntent, Slice>) obj).first);
dest.putBundle(OBJ_2, ((Pair<PendingIntent, Slice>) obj).second.toBundle());
break;
case FORMAT_TEXT:
dest.putCharSequence(OBJ, (CharSequence) obj);
break;
case FORMAT_COLOR:
dest.putInt(OBJ, (Integer) mObj);
break;
case FORMAT_TIMESTAMP:
dest.putLong(OBJ, (Long) mObj);
break;
}
}
private static Object readObj(String type, Bundle in) {
switch (type) {
case FORMAT_IMAGE:
case FORMAT_REMOTE_INPUT:
return in.getParcelable(OBJ);
case FORMAT_SLICE:
return new Slice(in.getBundle(OBJ));
case FORMAT_TEXT:
return in.getCharSequence(OBJ);
case FORMAT_ACTION:
return new Pair<>(
(PendingIntent) in.getParcelable(OBJ),
new Slice(in.getBundle(OBJ_2)));
case FORMAT_COLOR:
return in.getInt(OBJ);
case FORMAT_TIMESTAMP:
return in.getLong(OBJ);
}
throw new RuntimeException("Unsupported type " + type);
}
/**
* @hide
*/
@RestrictTo(Scope.LIBRARY)
public static String typeToString(String format) {
switch (format) {
case FORMAT_SLICE:
return "Slice";
case FORMAT_TEXT:
return "Text";
case FORMAT_IMAGE:
return "Image";
case FORMAT_ACTION:
return "Action";
case FORMAT_COLOR:
return "Color";
case FORMAT_TIMESTAMP:
return "Timestamp";
case FORMAT_REMOTE_INPUT:
return "RemoteInput";
}
return "Unrecognized format: " + format;
}
}