public final class

Slice

extends CustomVersionedParcelable

implements VersionedParcelable

 java.lang.Object

androidx.versionedparcelable.CustomVersionedParcelable

↳androidx.slice.Slice

Gradle dependencies

compile group: 'androidx.slice', name: 'slice-core', version: '1.1.0-alpha02'

  • groupId: androidx.slice
  • artifactId: slice-core
  • version: 1.1.0-alpha02

Artifact androidx.slice:slice-core:1.1.0-alpha02 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.slice:slice-core com.android.support:slices-core

Overview

A slice is a piece of app content and actions that can be surfaced outside of the app. A slice is identified by a Uri and served via a SliceProvider.

Slices are constructed using TemplateSliceBuilders in a tree structure that provides the OS some information about how the content should be displayed.

Summary

Fields
public static final java.lang.StringEXTRA_SELECTION

Key to retrieve an extra added to an intent when an item in a selection is selected.

public static final java.lang.StringSUBTYPE_RANGE_MODE

Subtype to tag an item as representing the progress bar mode for a

Constructors
publicSlice()

Used for VersionedParcelable

publicSlice(Bundle in)

Methods
public static voidappendHints(java.lang.StringBuilder sb, java.lang.String hints[])

public static SlicebindSlice(Context context, Uri uri, java.util.Set<SliceSpec> supportedSpecs)

Turns a slice Uri into slice content.

public java.lang.StringgetHintArray()

public java.util.List<java.lang.String>getHints()

public SliceItemgetItemArray()

public java.util.List<SliceItem>getItems()

public SliceSpecgetSpec()

public UrigetUri()

public booleanhasHint(java.lang.String hint)

public voidonPostParceling()

public voidonPreParceling(boolean isStream)

public BundletoBundle()

public java.lang.StringtoString()

public java.lang.StringtoString(java.lang.String indent)

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait

Fields

public static final java.lang.String EXTRA_SELECTION

Key to retrieve an extra added to an intent when an item in a selection is selected.

public static final java.lang.String SUBTYPE_RANGE_MODE

Subtype to tag an item as representing the progress bar mode for a

Constructors

public Slice()

Used for VersionedParcelable

public Slice(Bundle in)

Methods

public Bundle toBundle()

public SliceSpec getSpec()

Returns:

The spec for this slice

public Uri getUri()

Returns:

The Uri that this Slice represents.

public java.util.List<SliceItem> getItems()

Returns:

All child SliceItems that this Slice contains.

public SliceItem getItemArray()

Returns:

public java.util.List<java.lang.String> getHints()

Returns:

All hints associated with this Slice.

public java.lang.String getHintArray()

public boolean hasHint(java.lang.String hint)

public void onPreParceling(boolean isStream)

public void onPostParceling()

public java.lang.String toString()

Returns:

A string representation of this slice.

public java.lang.String toString(java.lang.String indent)

Returns:

A string representation of this slice.

public static void appendHints(java.lang.StringBuilder sb, java.lang.String hints[])

public static Slice bindSlice(Context context, Uri uri, java.util.Set<SliceSpec> supportedSpecs)

Turns a slice Uri into slice content.

Parameters:

context: Context to be used.
uri: The URI to a slice provider

Returns:

The Slice provided by the app or null if none is given.

See also: Slice

Source

/*
 * 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.slice;

import static android.app.slice.Slice.HINT_ACTIONS;
import static android.app.slice.Slice.HINT_ERROR;
import static android.app.slice.Slice.HINT_HORIZONTAL;
import static android.app.slice.Slice.HINT_KEYWORDS;
import static android.app.slice.Slice.HINT_LARGE;
import static android.app.slice.Slice.HINT_LAST_UPDATED;
import static android.app.slice.Slice.HINT_LIST;
import static android.app.slice.Slice.HINT_LIST_ITEM;
import static android.app.slice.Slice.HINT_NO_TINT;
import static android.app.slice.Slice.HINT_PARTIAL;
import static android.app.slice.Slice.HINT_PERMISSION_REQUEST;
import static android.app.slice.Slice.HINT_SEE_MORE;
import static android.app.slice.Slice.HINT_SELECTED;
import static android.app.slice.Slice.HINT_SHORTCUT;
import static android.app.slice.Slice.HINT_SUMMARY;
import static android.app.slice.Slice.HINT_TITLE;
import static android.app.slice.Slice.HINT_TTL;
import static android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_IMAGE;
import static android.app.slice.SliceItem.FORMAT_INT;
import static android.app.slice.SliceItem.FORMAT_LONG;
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 androidx.annotation.RestrictTo.Scope.LIBRARY;
import static androidx.slice.SliceConvert.unwrap;
import static androidx.slice.core.SliceHints.HINT_ACTIVITY;
import static androidx.slice.core.SliceHints.HINT_CACHED;
import static androidx.slice.core.SliceHints.HINT_END_OF_SECTION;
import static androidx.slice.core.SliceHints.HINT_OVERLAY;
import static androidx.slice.core.SliceHints.HINT_RAW;
import static androidx.slice.core.SliceHints.HINT_SELECTION_OPTION;
import static androidx.slice.core.SliceHints.HINT_SHOW_LABEL;

import android.app.PendingIntent;
import android.app.RemoteInput;
import android.app.slice.SliceManager;
import android.content.Context;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.annotation.StringDef;
import androidx.core.graphics.drawable.IconCompat;
import androidx.core.util.Preconditions;
import androidx.slice.compat.SliceProviderCompat;
import androidx.versionedparcelable.CustomVersionedParcelable;
import androidx.versionedparcelable.ParcelField;
import androidx.versionedparcelable.VersionedParcelable;
import androidx.versionedparcelable.VersionedParcelize;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * A slice is a piece of app content and actions that can be surfaced outside of the app. A slice
 * is identified by a Uri and served via a {@link SliceProvider}.
 *
 * <p>Slices are constructed using {@link androidx.slice.builders.TemplateSliceBuilder}s
 * in a tree structure that provides the OS some information about how the content should be
 * displayed.
 */
@VersionedParcelize(allowSerialization = true, isCustom = true)
@RequiresApi(19)
public final class Slice extends CustomVersionedParcelable implements VersionedParcelable {

    /**
     * Key to retrieve an extra added to an intent when an item in a selection is selected.
     */
    public static final String EXTRA_SELECTION = "android.app.slice.extra.SELECTION";

    /**
     * Subtype to tag an item as representing the progress bar mode for a
     * {@link android.app.slice.Slice#SUBTYPE_RANGE}
     *
     * @hide
     */
    @RestrictTo(Scope.LIBRARY_GROUP)
    public static final String SUBTYPE_RANGE_MODE = "range_mode";

    private static final String HINTS = "hints";
    private static final String ITEMS = "items";
    private static final String URI = "uri";
    private static final String SPEC_TYPE = "type";
    private static final String SPEC_REVISION = "revision";

    static final String[] NO_HINTS = new String[0];
    static final SliceItem[] NO_ITEMS = new SliceItem[0];

    /**
     * @hide
     */
    @RestrictTo(Scope.LIBRARY)
    @StringDef({
            HINT_TITLE,
            HINT_LIST,
            HINT_LIST_ITEM,
            HINT_LARGE,
            HINT_ACTIONS,
            HINT_SELECTED,
            HINT_HORIZONTAL,
            HINT_NO_TINT,
            HINT_PARTIAL,
            HINT_SUMMARY,
            HINT_SEE_MORE,
            HINT_SHORTCUT,
            HINT_KEYWORDS,
            HINT_TTL,
            HINT_LAST_UPDATED,
            HINT_PERMISSION_REQUEST,
            HINT_ERROR,
            HINT_ACTIVITY,
            HINT_CACHED,
            HINT_END_OF_SECTION,
            HINT_SELECTION_OPTION,
            HINT_RAW,
            HINT_OVERLAY,
            HINT_SHOW_LABEL
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface SliceHint { }

    @ParcelField(value = 1, defaultValue = "null")
    SliceSpec mSpec = null;

    @ParcelField(value = 2, defaultValue = "androidx.slice.Slice.NO_ITEMS")
    SliceItem[] mItems = NO_ITEMS;
    @ParcelField(value = 3, defaultValue = "androidx.slice.Slice.NO_HINTS")
    @SliceHint
    String[] mHints = NO_HINTS;
    @ParcelField(value = 4, defaultValue = "null")
    String mUri = null;

    /**
     * @hide
     */
    @RestrictTo(Scope.LIBRARY)
    Slice(ArrayList<SliceItem> items, @SliceHint String[] hints, Uri uri,
            SliceSpec spec) {
        mHints = hints;
        mItems = items.toArray(new SliceItem[items.size()]);
        mUri = uri.toString();
        mSpec = spec;
    }

    /**
     * Used for VersionedParcelable
     * @hide
     */
    @RestrictTo(Scope.LIBRARY)
    public Slice() {
    }

    /**
     * @hide
     */
    @RestrictTo(Scope.LIBRARY)
    public Slice(Bundle in) {
        mHints = in.getStringArray(HINTS);
        Parcelable[] items = in.getParcelableArray(ITEMS);
        mItems = new SliceItem[items.length];
        for (int i = 0; i < mItems.length; i++) {
            if (items[i] instanceof Bundle) {
                mItems[i] = new SliceItem((Bundle) items[i]);
            }
        }
        mUri = in.getParcelable(URI).toString();
        mSpec = in.containsKey(SPEC_TYPE)
                ? new SliceSpec(in.getString(SPEC_TYPE), in.getInt(SPEC_REVISION))
                : null;
    }

    /**
     * @hide
     */
    @RestrictTo(Scope.LIBRARY)
    public Bundle toBundle() {
        Bundle b = new Bundle();
        b.putStringArray(HINTS, mHints);
        Parcelable[] p = new Parcelable[mItems.length];
        for (int i = 0; i < mItems.length; i++) {
            p[i] = mItems[i].toBundle();
        }
        b.putParcelableArray(ITEMS, p);
        b.putParcelable(URI, Uri.parse(mUri));
        if (mSpec != null) {
            b.putString(SPEC_TYPE, mSpec.getType());
            b.putInt(SPEC_REVISION, mSpec.getRevision());
        }
        return b;
    }

    /**
     * @return The spec for this slice
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
    public @Nullable SliceSpec getSpec() {
        return mSpec;
    }

    /**
     * @return The Uri that this Slice represents.
     */
    public Uri getUri() {
        return Uri.parse(mUri);
    }

    /**
     * @return All child {@link SliceItem}s that this Slice contains.
     */
    public List<SliceItem> getItems() {
        return Arrays.asList(mItems);
    }

    /**
     * @hide
     * @return
     */
    @RestrictTo(LIBRARY)
    public SliceItem[] getItemArray() {
        return mItems;
    }

    /**
     * @return All hints associated with this Slice.
     */
    public @SliceHint List<String> getHints() {
        return Arrays.asList(mHints);
    }

    /**
     * @hide
     */
    @RestrictTo(LIBRARY)
    public @SliceHint String[] getHintArray() {
        return mHints;
    }

    /**
     * @hide
     */
    @RestrictTo(Scope.LIBRARY_GROUP_PREFIX)
    public boolean hasHint(@SliceHint String hint) {
        return ArrayUtils.contains(mHints, hint);
    }

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
    @Override
    public void onPreParceling(boolean isStream) {
    }

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
    @Override
    public void onPostParceling() {
        for (int i = mItems.length - 1; i >= 0; i--) {
            if (mItems[i].mObj == null) {
                mItems = ArrayUtils.removeElement(SliceItem.class, mItems, mItems[i]);
                if (mItems == null) {
                    mItems = new SliceItem[0];
                }
            }
        }
    }

    /**
     * A Builder used to construct {@link Slice}s
     * @hide
     */
    @RestrictTo(Scope.LIBRARY_GROUP_PREFIX)
    public static class Builder {

        private final Uri mUri;
        private ArrayList<SliceItem> mItems = new ArrayList<>();
        private @SliceHint ArrayList<String> mHints = new ArrayList<>();
        private SliceSpec mSpec;
        private int mChildId;

        /**
         * Create a builder which will construct a {@link Slice} for the Given Uri.
         * @param uri Uri to tag for this slice.
         */
        public Builder(@NonNull Uri uri) {
            mUri = uri;
        }

        /**
         * Create a builder for a {@link Slice} that is a sub-slice of the slice
         * being constructed by the provided builder.
         * @param parent The builder constructing the parent slice
         */
        public Builder(@NonNull Slice.Builder parent) {
            mUri = parent.getChildUri();
        }

        private Uri getChildUri() {
            return mUri.buildUpon().appendPath("_gen")
                    .appendPath(String.valueOf(mChildId++)).build();
        }

        /**
         * Add the spec for this slice.
         * @hide
         */
        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
        public Builder setSpec(SliceSpec spec) {
            mSpec = spec;
            return this;
        }

        /**
         * Add hints to the Slice being constructed
         */
        public Builder addHints(@SliceHint String... hints) {
            mHints.addAll(Arrays.asList(hints));
            return this;
        }

        /**
         * Add hints to the Slice being constructed
         */
        public Builder addHints(@SliceHint List<String> hints) {
            return addHints(hints.toArray(new String[hints.size()]));
        }

        /**
         * Add a sub-slice to the slice being constructed
         */
        public Builder addSubSlice(@NonNull Slice slice) {
            Preconditions.checkNotNull(slice);
            return addSubSlice(slice, null);
        }

        /**
         * Add a sub-slice to the slice being constructed
         * @param subType Optional template-specific type information
         * @see SliceItem#getSubType()
         */
        public Builder addSubSlice(@NonNull Slice slice, String subType) {
            Preconditions.checkNotNull(slice);
            mItems.add(new SliceItem(slice, FORMAT_SLICE, subType, slice.getHintArray()));
            return this;
        }

        /**
         * Add an action to the slice being constructed
         * @param subType Optional template-specific type information
         * @see SliceItem#getSubType()
         */
        public Slice.Builder addAction(@NonNull PendingIntent action,
                @NonNull Slice s, @Nullable String subType) {
            Preconditions.checkNotNull(action);
            Preconditions.checkNotNull(s);
            @SliceHint String[] hints = s.getHintArray();
            mItems.add(new SliceItem(action, s, FORMAT_ACTION, subType, hints));
            return this;
        }

        /**
         * Add an action to the slice being constructed
         * @param subType Optional template-specific type information
         * @param action Callback to be triggered when a pending intent would normally be fired.
         * @see SliceItem#getSubType()
         */
        public Slice.Builder addAction(@NonNull SliceItem.ActionHandler action,
                @NonNull Slice s, @Nullable String subType) {
            Preconditions.checkNotNull(s);
            @SliceHint String[] hints = s.getHintArray();
            mItems.add(new SliceItem(action, s, FORMAT_ACTION, subType, hints));
            return this;
        }

        /**
         * Add text to the slice being constructed
         * @param subType Optional template-specific type information
         * @see SliceItem#getSubType()
         */
        public Builder addText(CharSequence text, @Nullable String subType,
                @SliceHint String... hints) {
            mItems.add(new SliceItem(text, FORMAT_TEXT, subType, hints));
            return this;
        }

        /**
         * Add text to the slice being constructed
         * @param subType Optional template-specific type information
         * @see SliceItem#getSubType()
         */
        public Builder addText(CharSequence text, @Nullable String subType,
                @SliceHint List<String> hints) {
            return addText(text, subType, hints.toArray(new String[hints.size()]));
        }

        /**
         * Add an image to the slice being constructed
         * @param subType Optional template-specific type information
         * @see SliceItem#getSubType()
         */
        public Builder addIcon(IconCompat icon, @Nullable String subType,
                @SliceHint String... hints) {
            Preconditions.checkNotNull(icon);
            if (isValidIcon(icon)) {
                mItems.add(new SliceItem(icon, FORMAT_IMAGE, subType, hints));
            }
            return this;
        }

        /**
         * Add an image to the slice being constructed
         * @param subType Optional template-specific type information
         * @see SliceItem#getSubType()
         */
        public Builder addIcon(IconCompat icon, @Nullable String subType,
                @SliceHint List<String> hints) {
            Preconditions.checkNotNull(icon);
            if (isValidIcon(icon)) {
                return addIcon(icon, subType, hints.toArray(new String[hints.size()]));
            }
            return this;
        }

        /**
         * Add remote input to the slice being constructed
         * @param subType Optional template-specific type information
         * @see SliceItem#getSubType()
         * @hide
         */
        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
        public Slice.Builder addRemoteInput(RemoteInput remoteInput, @Nullable String subType,
                @SliceHint List<String> hints) {
            Preconditions.checkNotNull(remoteInput);
            return addRemoteInput(remoteInput, subType, hints.toArray(new String[hints.size()]));
        }

        /**
         * Add remote input to the slice being constructed
         * @param subType Optional template-specific type information
         * @see SliceItem#getSubType()
         * @hide
         */
        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
        public Slice.Builder addRemoteInput(RemoteInput remoteInput, @Nullable String subType,
                @SliceHint String... hints) {
            Preconditions.checkNotNull(remoteInput);
            mItems.add(new SliceItem(remoteInput, FORMAT_REMOTE_INPUT, subType, hints));
            return this;
        }

        /**
         * Add a int to the slice being constructed
         * @param subType Optional template-specific type information
         * @see SliceItem#getSubType()
         */
        public Builder addInt(int value, @Nullable String subType,
                @SliceHint String... hints) {
            mItems.add(new SliceItem(value, FORMAT_INT, subType, hints));
            return this;
        }

        /**
         * Add a int to the slice being constructed
         *
         * @param subType Optional template-specific type information
         * @see SliceItem#getSubType()
         */
        public Builder addInt(int value, @Nullable String subType,
                @SliceHint List<String> hints) {
            return addInt(value, subType, hints.toArray(new String[hints.size()]));
        }

        /**
         * Add a long to the slice being constructed
         * @param subType Optional template-specific type information
         * @see SliceItem#getSubType()
         */
        public Slice.Builder addLong(long time, @Nullable String subType,
                @SliceHint String... hints) {
            mItems.add(new SliceItem(time, FORMAT_LONG, subType, hints));
            return this;
        }

        /**
         * Add a long to the slice being constructed
         * @param subType Optional template-specific type information
         * @see SliceItem#getSubType()
         */
        public Slice.Builder addLong(long time, @Nullable String subType,
                @SliceHint List<String> hints) {
            return addLong(time, subType, hints.toArray(new String[hints.size()]));
        }

        /**
         * Add a timestamp to the slice being constructed
         * @param subType Optional template-specific type information
         * @see SliceItem#getSubType()
         * @deprecated TO BE REMOVED
         */
        @Deprecated
        public Slice.Builder addTimestamp(long time, @Nullable String subType,
                @SliceHint String... hints) {
            mItems.add(new SliceItem(time, FORMAT_LONG, subType, hints));
            return this;
        }

        /**
         * Add a timestamp to the slice being constructed
         * @param subType Optional template-specific type information
         * @see SliceItem#getSubType()
         */
        public Slice.Builder addTimestamp(long time, @Nullable String subType,
                @SliceHint List<String> hints) {
            return addTimestamp(time, subType, hints.toArray(new String[hints.size()]));
        }

        /**
         * Add a SliceItem to the slice being constructed.
         * @hide
         */
        @RestrictTo(Scope.LIBRARY_GROUP)
        public Slice.Builder addItem(SliceItem item) {
            mItems.add(item);
            return this;
        }

        /**
         * Construct the slice.
         */
        public Slice build() {
            return new Slice(mItems, mHints.toArray(new String[mHints.size()]), mUri, mSpec);
        }
    }

    /**
     * @return A string representation of this slice.
     */
    @Override
    public String toString() {
        return toString("");
    }

    /**
     * @return A string representation of this slice.
     * @hide
     */
    @RestrictTo(Scope.LIBRARY)
    public String toString(String indent) {
        StringBuilder sb = new StringBuilder();
        sb.append(indent);
        sb.append("Slice ");
        if (mHints.length > 0) {
            appendHints(sb, mHints);
            sb.append(' ');
        }
        sb.append('[');
        sb.append(mUri);
        sb.append("] {\n");
        final String nextIndent = indent + "  ";
        for (int i = 0; i < mItems.length; i++) {
            SliceItem item = mItems[i];
            sb.append(item.toString(nextIndent));
        }
        sb.append(indent);
        sb.append('}');
        return sb.toString();
    }

    /**
     * @hide
     */
    @RestrictTo(Scope.LIBRARY)
    public static void appendHints(StringBuilder sb, String[] hints) {
        if (hints == null || hints.length == 0) return;

        sb.append('(');
        int end = hints.length - 1;
        for (int i = 0; i < end; i++) {
            sb.append(hints[i]);
            sb.append(", ");
        }
        sb.append(hints[end]);
        sb.append(")");
    }

    /**
     * Turns a slice Uri into slice content.
     *
     * @param context Context to be used.
     * @param uri The URI to a slice provider
     * @return The Slice provided by the app or null if none is given.
     * @hide
     * @see Slice
     */
    @RestrictTo(Scope.LIBRARY_GROUP_PREFIX)
    @Nullable
    public static Slice bindSlice(Context context, @NonNull Uri uri,
            Set<SliceSpec> supportedSpecs) {
        if (Build.VERSION.SDK_INT >= 28) {
            return callBindSlice(context, uri, supportedSpecs);
        } else {
            return SliceProviderCompat.bindSlice(context, uri, supportedSpecs);
        }
    }

    @RequiresApi(28)
    private static Slice callBindSlice(Context context, Uri uri,
            Set<SliceSpec> supportedSpecs) {
        return SliceConvert.wrap(context.getSystemService(SliceManager.class)
                .bindSlice(uri, unwrap(supportedSpecs)), context);
    }

    /**
     * @hide
     */
    @RestrictTo(LIBRARY)
    static boolean isValidIcon(IconCompat icon) {
        if (icon == null) {
            return false;
        }
        if (icon.mType == Icon.TYPE_RESOURCE && icon.getResId() == 0) {
            throw new IllegalArgumentException("Failed to add icon, invalid resource id: "
                    + icon.getResId());
        }
        return true;
    }
}