Compat for slices

Support back to v19.

Test: Run samples on API 28 and API 27
Change-Id: Ib8f7b30575f6c2126eab4a285780a68858629396
diff --git a/samples/SupportSliceDemos/src/main/AndroidManifest.xml b/samples/SupportSliceDemos/src/main/AndroidManifest.xml
index 232724c..2ee7667 100644
--- a/samples/SupportSliceDemos/src/main/AndroidManifest.xml
+++ b/samples/SupportSliceDemos/src/main/AndroidManifest.xml
@@ -44,7 +44,8 @@
 
         <provider android:authorities="com.example.androidx.slice.demos"
                   android:name=".SampleSliceProvider"
-                  android:grantUriPermissions="true" />
+                  android:grantUriPermissions="true">
+        </provider>
 
         <receiver
             android:name=".SliceBroadcastReceiver"
diff --git a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
index 06de29a..d143c44 100644
--- a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
+++ b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
@@ -16,25 +16,26 @@
 
 package com.example.androidx.slice.demos;
 
+import static android.app.slice.Slice.HINT_SELECTED;
+import static android.app.slice.Slice.HINT_TITLE;
+
 import android.app.PendingIntent;
-import android.app.slice.Slice;
-import android.app.slice.SliceProvider;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.provider.Settings;
-import android.support.annotation.RequiresApi;
 import android.text.format.DateUtils;
 
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceProvider;
 import androidx.app.slice.builders.MessagingSliceBuilder;
 import androidx.app.slice.core.SliceHints;
 
 /**
  * Examples of using slice template builders.
  */
-@RequiresApi(api = 28)
 public class SampleSliceProvider extends SliceProvider {
     public static final Uri MESSAGE =
             Uri.parse("content://com.example.androidx.slice.demos/message");
@@ -45,7 +46,7 @@
             "com.android.settings.slice.action.WIFI_CHANGED";
 
     @Override
-    public boolean onCreate() {
+    public boolean onCreateSliceProvider() {
         return true;
     }
 
@@ -107,7 +108,7 @@
                 break;
         }
         if (wifiEnabled) {
-            toggleHints = new String[] {SliceHints.HINT_TOGGLE, Slice.HINT_SELECTED};
+            toggleHints = new String[] {SliceHints.HINT_TOGGLE, HINT_SELECTED};
         } else {
             toggleHints = new String[] {SliceHints.HINT_TOGGLE};
         }
@@ -120,12 +121,12 @@
                                 .addText(state, null)
                                 .addIcon(Icon.createWithResource(getContext(),
                                         R.drawable.ic_settings_wifi), null, SliceHints.HINT_HIDDEN)
-                                .addHints(Slice.HINT_TITLE)
-                                .build())
+                                .addHints(HINT_TITLE)
+                                .build(), null)
                 .addAction(getBroadcastIntent(ACTION_WIFI_CHANGED),
                         new Slice.Builder(b)
                                 .addHints(toggleHints)
-                                .build())
+                                .build(), null)
                 .build());
         return b.build();
     }
diff --git a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
index a4f28c1..0d5e153 100644
--- a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
+++ b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
@@ -16,7 +16,6 @@
 
 package com.example.androidx.slice.demos;
 
-import android.app.slice.Slice;
 import android.arch.lifecycle.LiveData;
 import android.content.ContentResolver;
 import android.content.pm.ActivityInfo;
@@ -44,6 +43,7 @@
 import java.util.Comparator;
 import java.util.List;
 
+import androidx.app.slice.Slice;
 import androidx.app.slice.widget.SliceLiveData;
 import androidx.app.slice.widget.SliceView;
 
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/MessagingSliceBuilder.java b/slices/builders/src/main/java/androidx/app/slice/builders/MessagingSliceBuilder.java
index bf59a5a..816fddd 100644
--- a/slices/builders/src/main/java/androidx/app/slice/builders/MessagingSliceBuilder.java
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/MessagingSliceBuilder.java
@@ -18,12 +18,13 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.app.slice.Slice;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.support.annotation.NonNull;
 import android.support.annotation.RestrictTo;
 
+import androidx.app.slice.Slice;
+
 /**
  * Builder to construct slice content in a messaging format.
  */
@@ -58,7 +59,7 @@
 
     @Override
     public void add(SubTemplateSliceBuilder builder) {
-        getBuilder().addSubSlice(builder.build(), Slice.SUBTYPE_MESSAGE);
+        getBuilder().addSubSlice(builder.build(), android.app.slice.Slice.SUBTYPE_MESSAGE);
     }
 
     /**
@@ -78,7 +79,7 @@
          * Add the icon used to display contact in the messaging experience
          */
         public MessageBuilder addSource(Icon source) {
-            getBuilder().addIcon(source, Slice.SUBTYPE_SOURCE);
+            getBuilder().addIcon(source, android.app.slice.Slice.SUBTYPE_SOURCE);
             return this;
         }
 
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/TemplateSliceBuilder.java b/slices/builders/src/main/java/androidx/app/slice/builders/TemplateSliceBuilder.java
index 61fea7f..102ee00 100644
--- a/slices/builders/src/main/java/androidx/app/slice/builders/TemplateSliceBuilder.java
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/TemplateSliceBuilder.java
@@ -17,10 +17,11 @@
 package androidx.app.slice.builders;
 
 
-import android.app.slice.Slice;
 import android.net.Uri;
 import android.support.annotation.RestrictTo;
 
+import androidx.app.slice.Slice;
+
 /**
  * Base class of builders of various template types.
  */
diff --git a/slices/core/build.gradle b/slices/core/build.gradle
index b145ded..237389a 100644
--- a/slices/core/build.gradle
+++ b/slices/core/build.gradle
@@ -20,12 +20,19 @@
 
 dependencies {
     implementation libs.support.annotations, libs.support_exclude_config
+    implementation libs.support.app_compat, libs.support_exclude_config
 }
 
 android {
     defaultConfig {
         minSdkVersion 28
     }
+    sourceSets {
+        main.res.srcDirs = [
+                'res',
+                'res-public'
+        ]
+    }
 }
 
 supportLibrary {
diff --git a/slices/core/src/main/java/androidx/app/slice/ArrayUtils.java b/slices/core/src/main/java/androidx/app/slice/ArrayUtils.java
new file mode 100644
index 0000000..669f66a
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/ArrayUtils.java
@@ -0,0 +1,75 @@
+/*
+ * 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 android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+
+import java.lang.reflect.Array;
+import java.util.Objects;
+
+/**
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+class ArrayUtils {
+
+    public static <T> boolean contains(T[] array, T item) {
+        for (T t : array) {
+            if (Objects.equals(t, item)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static <T> T[] appendElement(Class<T> kind, T[] array, T element) {
+        final T[] result;
+        final int end;
+        if (array != null) {
+            end = array.length;
+            result = (T[]) Array.newInstance(kind, end + 1);
+            System.arraycopy(array, 0, result, 0, end);
+        } else {
+            end = 0;
+            result = (T[]) Array.newInstance(kind, 1);
+        }
+        result[end] = element;
+        return result;
+    }
+
+    public static <T> T[] removeElement(Class<T> kind, T[] array, T element) {
+        if (array != null) {
+            if (!contains(array, element)) {
+                return array;
+            }
+            final int length = array.length;
+            for (int i = 0; i < length; i++) {
+                if (Objects.equals(array[i], element)) {
+                    if (length == 1) {
+                        return null;
+                    }
+                    T[] result = (T[]) Array.newInstance(kind, length - 1);
+                    System.arraycopy(array, 0, result, 0, i);
+                    System.arraycopy(array, i + 1, result, i, length - i - 1);
+                    return result;
+                }
+            }
+        }
+        return array;
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/Slice.java b/slices/core/src/main/java/androidx/app/slice/Slice.java
new file mode 100644
index 0000000..e7c6284
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/Slice.java
@@ -0,0 +1,406 @@
+/*
+ * 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.Slice.HINT_ACTIONS;
+import static android.app.slice.Slice.HINT_HORIZONTAL;
+import static android.app.slice.Slice.HINT_LARGE;
+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_SELECTED;
+import static android.app.slice.Slice.HINT_TITLE;
+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.content.ContentProvider;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.support.annotation.StringDef;
+import android.support.v4.os.BuildCompat;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import androidx.app.slice.compat.SliceProviderCompat;
+import androidx.app.slice.core.SliceHints;
+import androidx.app.slice.core.SliceSpecs;
+
+/**
+ * A slice is a piece of app content and actions that can be surfaced outside of the app.
+ *
+ * <p>They are constructed using {@link Builder} in a tree structure
+ * that provides the OS some information about how the content should be displayed.
+ */
+public final class Slice {
+
+    private static final String HINTS = "hints";
+    private static final String ITEMS = "items";
+    private static final String URI = "uri";
+
+    /**
+     * @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,
+            SliceHints.HINT_HIDDEN, SliceHints.HINT_TOGGLE})
+    public @interface SliceHint{ }
+
+    private final SliceItem[] mItems;
+    private final @SliceHint String[] mHints;
+    private Uri mUri;
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    Slice(ArrayList<SliceItem> items, @SliceHint String[] hints, Uri uri) {
+        mHints = hints;
+        mItems = items.toArray(new SliceItem[items.size()]);
+        mUri = uri;
+    }
+
+    /**
+     * @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);
+    }
+
+    /**
+     * @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, mUri);
+        return b;
+    }
+
+    /**
+     * @return The Uri that this Slice represents.
+     */
+    public Uri getUri() {
+        return mUri;
+    }
+
+    /**
+     * @return All child {@link SliceItem}s that this Slice contains.
+     */
+    public List<SliceItem> getItems() {
+        return Arrays.asList(mItems);
+    }
+
+    /**
+     * @return All hints associated with this Slice.
+     */
+    public @SliceHint List<String> getHints() {
+        return Arrays.asList(mHints);
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    public boolean hasHint(@SliceHint String hint) {
+        return ArrayUtils.contains(mHints, hint);
+    }
+
+    /**
+     * A Builder used to construct {@link Slice}s
+     */
+    public static class Builder {
+
+        private final Uri mUri;
+        private ArrayList<SliceItem> mItems = new ArrayList<>();
+        private @SliceHint ArrayList<String> mHints = new ArrayList<>();
+
+        /**
+         * 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.mUri.buildUpon().appendPath("_gen")
+                    .appendPath(String.valueOf(mItems.size())).build();
+        }
+
+        /**
+         * 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) {
+            return addSubSlice(slice, null);
+        }
+
+        /**
+         * Add a sub-slice to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Builder addSubSlice(@NonNull Slice slice, String subType) {
+            mItems.add(new SliceItem(slice, FORMAT_SLICE, subType, slice.getHints().toArray(
+                    new String[slice.getHints().size()])));
+            return this;
+        }
+
+        /**
+         * Add an action to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Slice.Builder addAction(@NonNull PendingIntent action,
+                @NonNull Slice s, @Nullable String subType) {
+            mItems.add(new SliceItem(action, s, FORMAT_ACTION, subType, new String[0]));
+            return this;
+        }
+
+        /**
+         * Add text to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link 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 {@link 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 {@link SliceItem#getSubType()}
+         */
+        public Builder addIcon(Icon icon, @Nullable String subType,
+                @SliceHint String... hints) {
+            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 {@link SliceItem#getSubType()}
+         */
+        public Builder addIcon(Icon icon, @Nullable String subType,
+                @SliceHint List<String> hints) {
+            return addIcon(icon, subType, hints.toArray(new String[hints.size()]));
+        }
+
+        /**
+         * Add remote input to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Slice.Builder addRemoteInput(RemoteInput remoteInput, @Nullable String subType,
+                @SliceHint List<String> hints) {
+            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 {@link SliceItem#getSubType()}
+         */
+        public Slice.Builder addRemoteInput(RemoteInput remoteInput, @Nullable String subType,
+                @SliceHint String... hints) {
+            mItems.add(new SliceItem(remoteInput, FORMAT_REMOTE_INPUT, subType, hints));
+            return this;
+        }
+
+        /**
+         * Add a color to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Builder addColor(int color, @Nullable String subType,
+                @SliceHint String... hints) {
+            mItems.add(new SliceItem(color, FORMAT_COLOR, subType, hints));
+            return this;
+        }
+
+        /**
+         * Add a color to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Builder addColor(int color, @Nullable String subType,
+                @SliceHint List<String> hints) {
+            return addColor(color, subType, hints.toArray(new String[hints.size()]));
+        }
+
+        /**
+         * Add a timestamp to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Slice.Builder addTimestamp(long time, @Nullable String subType,
+                @SliceHint String... hints) {
+            mItems.add(new SliceItem(time, FORMAT_TIMESTAMP, subType, hints));
+            return this;
+        }
+
+        /**
+         * Add a timestamp to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link 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()]));
+        }
+
+        /**
+         * Construct the slice.
+         */
+        public Slice build() {
+            return new Slice(mItems, mHints.toArray(new String[mHints.size()]), mUri);
+        }
+    }
+
+    /**
+     * @hide
+     * @return A string representation of this slice.
+     */
+    @RestrictTo(Scope.LIBRARY)
+    @Override
+    public String toString() {
+        return toString("");
+    }
+
+    private String toString(String indent) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < mItems.length; i++) {
+            sb.append(indent);
+            if (FORMAT_SLICE.equals(mItems[i].getFormat())) {
+                sb.append("slice:\n");
+                sb.append(mItems[i].getSlice().toString(indent + "   "));
+            } else if (FORMAT_TEXT.equals(mItems[i].getFormat())) {
+                sb.append("text: ");
+                sb.append(mItems[i].getText());
+                sb.append("\n");
+            } else {
+                sb.append(SliceItem.typeToString(mItems[i].getFormat()));
+                sb.append("\n");
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 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.
+     * @see Slice
+     */
+    public static @Nullable Slice bindSlice(Context context, @NonNull Uri uri) {
+        if (BuildCompat.isAtLeastP()) {
+            return SliceConvert.wrap(android.app.slice.Slice.bindSlice(
+                    context.getContentResolver(), uri, SliceSpecs.SUPPORTED_SPECS));
+        } else {
+            return SliceProviderCompat.bindSlice(context, uri);
+        }
+    }
+
+    /**
+     * Turns a slice intent into slice content. Expects an explicit intent. If there is no
+     * {@link ContentProvider} associated with the given intent this will throw
+     * {@link IllegalArgumentException}.
+     *
+     * @param context The context to use.
+     * @param intent The intent associated with a slice.
+     * @return The Slice provided by the app or null if none is given.
+     * @see Slice
+     * @see SliceProvider#onMapIntentToUri(Intent)
+     * @see Intent
+     */
+    public static @Nullable Slice bindSlice(Context context, @NonNull Intent intent) {
+        if (BuildCompat.isAtLeastP()) {
+            return SliceConvert.wrap(android.app.slice.Slice.bindSlice(
+                    context, intent, SliceSpecs.SUPPORTED_SPECS));
+        } else {
+            return SliceProviderCompat.bindSlice(context, intent);
+        }
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/SliceConvert.java b/slices/core/src/main/java/androidx/app/slice/SliceConvert.java
new file mode 100644
index 0000000..1c87b56
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/SliceConvert.java
@@ -0,0 +1,103 @@
+/*
+ * 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;
+
+/**
+ * Convert between {@link androidx.app.slice.Slice} and {@link android.app.slice.Slice}
+ */
+public class SliceConvert {
+
+    /**
+     * Convert {@link androidx.app.slice.Slice} to {@link android.app.slice.Slice}
+     */
+    public static android.app.slice.Slice unwrap(androidx.app.slice.Slice slice) {
+        android.app.slice.Slice.Builder builder = new android.app.slice.Slice.Builder(
+                slice.getUri());
+        builder.addHints(slice.getHints());
+        for (androidx.app.slice.SliceItem item : slice.getItems()) {
+            switch (item.getFormat()) {
+                case FORMAT_SLICE:
+                    builder.addSubSlice(unwrap(item.getSlice()), item.getSubType());
+                    break;
+                case FORMAT_IMAGE:
+                    builder.addIcon(item.getIcon(), item.getSubType(), item.getHints());
+                    break;
+                case FORMAT_REMOTE_INPUT:
+                    builder.addRemoteInput(item.getRemoteInput(), item.getSubType(),
+                            item.getHints());
+                    break;
+                case FORMAT_ACTION:
+                    builder.addAction(item.getAction(), unwrap(item.getSlice()), item.getSubType());
+                    break;
+                case FORMAT_TEXT:
+                    builder.addText(item.getText(), item.getSubType(), item.getHints());
+                    break;
+                case FORMAT_COLOR:
+                    builder.addColor(item.getColor(), item.getSubType(), item.getHints());
+                    break;
+                case FORMAT_TIMESTAMP:
+                    builder.addTimestamp(item.getTimestamp(), item.getSubType(), item.getHints());
+                    break;
+            }
+        }
+        return builder.build();
+    }
+
+    /**
+     * Convert {@link android.app.slice.Slice} to {@link androidx.app.slice.Slice}
+     */
+    public static androidx.app.slice.Slice wrap(android.app.slice.Slice slice) {
+        androidx.app.slice.Slice.Builder builder = new androidx.app.slice.Slice.Builder(
+                slice.getUri());
+        builder.addHints(slice.getHints());
+        for (android.app.slice.SliceItem item : slice.getItems()) {
+            switch (item.getFormat()) {
+                case FORMAT_SLICE:
+                    builder.addSubSlice(wrap(item.getSlice()), item.getSubType());
+                    break;
+                case FORMAT_IMAGE:
+                    builder.addIcon(item.getIcon(), item.getSubType(), item.getHints());
+                    break;
+                case FORMAT_REMOTE_INPUT:
+                    builder.addRemoteInput(item.getRemoteInput(), item.getSubType(),
+                            item.getHints());
+                    break;
+                case FORMAT_ACTION:
+                    builder.addAction(item.getAction(), wrap(item.getSlice()), item.getSubType());
+                    break;
+                case FORMAT_TEXT:
+                    builder.addText(item.getText(), item.getSubType(), item.getHints());
+                    break;
+                case FORMAT_COLOR:
+                    builder.addColor(item.getColor(), item.getSubType(), item.getHints());
+                    break;
+                case FORMAT_TIMESTAMP:
+                    builder.addTimestamp(item.getTimestamp(), item.getSubType(), item.getHints());
+                    break;
+            }
+        }
+        return builder.build();
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/SliceItem.java b/slices/core/src/main/java/androidx/app/slice/SliceItem.java
new file mode 100644
index 0000000..031d43c
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/SliceItem.java
@@ -0,0 +1,348 @@
+/*
+ * 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.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
+     */
+    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
+     */
+    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.getParcelable(OBJ));
+            case FORMAT_TEXT:
+                return in.getCharSequence(OBJ);
+            case FORMAT_ACTION:
+                return new Pair<PendingIntent, Slice>(
+                        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;
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/SliceProvider.java b/slices/core/src/main/java/androidx/app/slice/SliceProvider.java
new file mode 100644
index 0000000..a0c12f1
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/SliceProvider.java
@@ -0,0 +1,130 @@
+/*
+ * 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 android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ProviderInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.v4.os.BuildCompat;
+
+import androidx.app.slice.compat.ContentProviderWrapper;
+import androidx.app.slice.compat.SliceProviderCompat;
+import androidx.app.slice.compat.SliceProviderWrapper;
+
+/**
+ * A SliceProvider allows an app to provide content to be displayed in system spaces. This content
+ * is templated and can contain actions, and the behavior of how it is surfaced is specific to the
+ * system surface.
+ * <p>
+ * Slices are not currently live content. They are bound once and shown to the user. If the content
+ * changes due to a callback from user interaction, then
+ * {@link ContentResolver#notifyChange(Uri, ContentObserver)} should be used to notify the system.
+ * </p>
+ * <p>
+ * The provider needs to be declared in the manifest to provide the authority for the app. The
+ * authority for most slices is expected to match the package of the application.
+ * </p>
+ *
+ * <pre class="prettyprint">
+ * {@literal
+ * <provider
+ *     android:name="com.android.mypkg.MySliceProvider"
+ *     android:authorities="com.android.mypkg" />}
+ * </pre>
+ * <p>
+ * Slices can be identified by a Uri or by an Intent. To link an Intent with a slice, the provider
+ * must have an {@link IntentFilter} matching the slice intent. When a slice is being requested via
+ * an intent, {@link #onMapIntentToUri(Intent)} can be called and is expected to return an
+ * appropriate Uri representing the slice.
+ *
+ * <pre class="prettyprint">
+ * {@literal
+ * <provider
+ *     android:name="com.android.mypkg.MySliceProvider"
+ *     android:authorities="com.android.mypkg">
+ *     <intent-filter>
+ *         <action android:name="android.intent.action.MY_SLICE_INTENT" />
+ *     </intent-filter>
+ * </provider>}
+ * </pre>
+ *
+ * @see android.app.slice.Slice
+ */
+public abstract class SliceProvider extends ContentProviderWrapper {
+
+    @Override
+    public void attachInfo(Context context, ProviderInfo info) {
+        ContentProvider impl;
+        if (BuildCompat.isAtLeastP()) {
+            impl = new SliceProviderWrapper(this);
+        } else {
+            impl = new SliceProviderCompat(this);
+        }
+        super.attachInfo(context, info, impl);
+    }
+
+    /**
+     * Implement this to initialize your slice provider on startup.
+     * This method is called for all registered slice providers on the
+     * application main thread at application launch time.  It must not perform
+     * lengthy operations, or application startup will be delayed.
+     *
+     * <p>You should defer nontrivial initialization (such as opening,
+     * upgrading, and scanning databases) until the slice provider is used
+     * (via #onBindSlice, etc).  Deferred initialization
+     * keeps application startup fast, avoids unnecessary work if the provider
+     * turns out not to be needed, and stops database errors (such as a full
+     * disk) from halting application launch.
+     *
+     * @return true if the provider was successfully loaded, false otherwise
+     */
+    public abstract boolean onCreateSliceProvider();
+
+    /**
+     * Implemented to create a slice. Will be called on the main thread.
+     * <p>
+     * onBindSlice should return as quickly as possible so that the UI tied
+     * to this slice can be responsive. No network or other IO will be allowed
+     * during onBindSlice. Any loading that needs to be done should happen
+     * off the main thread with a call to {@link ContentResolver#notifyChange(Uri, ContentObserver)}
+     * when the app is ready to provide the complete data in onBindSlice.
+     * <p>
+     *
+     * @see {@link Slice}.
+     * @see {@link android.app.slice.Slice#HINT_PARTIAL}
+     */
+    // TODO: Provide alternate notifyChange that takes in the slice (i.e. notifyChange(Uri, Slice)).
+    public abstract Slice onBindSlice(Uri sliceUri);
+
+    /**
+     * This method must be overridden if an {@link IntentFilter} is specified on the SliceProvider.
+     * In that case, this method can be called and is expected to return a non-null Uri representing
+     * a slice. Otherwise this will throw {@link UnsupportedOperationException}.
+     *
+     * @return Uri representing the slice associated with the provided intent.
+     * @see {@link android.app.slice.Slice}
+     */
+    public @NonNull Uri onMapIntentToUri(Intent intent) {
+        throw new UnsupportedOperationException(
+                "This provider has not implemented intent to uri mapping");
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/compat/ContentProviderWrapper.java b/slices/core/src/main/java/androidx/app/slice/compat/ContentProviderWrapper.java
new file mode 100644
index 0000000..9da25ac
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/compat/ContentProviderWrapper.java
@@ -0,0 +1,119 @@
+/*
+ * 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.compat;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.ProviderInfo;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+
+/**
+ * @hide
+ */
+// TODO: Remove as soon as we have better systems in place for this.
+@RestrictTo(Scope.LIBRARY)
+public class ContentProviderWrapper extends ContentProvider {
+
+    private ContentProvider mImpl;
+
+    /**
+     * Triggers an attach with the object to wrap.
+     */
+    public void attachInfo(Context context, ProviderInfo info, ContentProvider impl) {
+        mImpl = impl;
+        mImpl.attachInfo(context, info);
+        super.attachInfo(context, info);
+    }
+
+    @Override
+    public final boolean onCreate() {
+        return mImpl.onCreate();
+    }
+
+    @Nullable
+    @Override
+    public final Cursor query(@NonNull Uri uri, @Nullable String[] projection,
+            @Nullable String selection, @Nullable String[] selectionArgs,
+            @Nullable String sortOrder) {
+        return mImpl.query(uri, projection, selection, selectionArgs, sortOrder);
+    }
+
+    @Nullable
+    @Override
+    public final Cursor query(@NonNull Uri uri, @Nullable String[] projection,
+            @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal) {
+        return mImpl.query(uri, projection, queryArgs, cancellationSignal);
+    }
+
+    @Nullable
+    @Override
+    public final Cursor query(@NonNull Uri uri, @Nullable String[] projection,
+            @Nullable String selection, @Nullable String[] selectionArgs,
+            @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) {
+        return mImpl.query(uri, projection, selection, selectionArgs, sortOrder,
+                cancellationSignal);
+    }
+
+    @Nullable
+    @Override
+    public final String getType(@NonNull Uri uri) {
+        return mImpl.getType(uri);
+    }
+
+    @Nullable
+    @Override
+    public final Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
+        return mImpl.insert(uri, values);
+    }
+
+    @Override
+    public final int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) {
+        return mImpl.bulkInsert(uri, values);
+    }
+
+    @Override
+    public final int delete(@NonNull Uri uri, @Nullable String selection,
+            @Nullable String[] selectionArgs) {
+        return mImpl.delete(uri, selection, selectionArgs);
+    }
+
+    @Override
+    public final int update(@NonNull Uri uri, @Nullable ContentValues values,
+            @Nullable String selection, @Nullable String[] selectionArgs) {
+        return mImpl.update(uri, values, selection, selectionArgs);
+    }
+
+    @Nullable
+    @Override
+    public final Bundle call(@NonNull String method, @Nullable String arg,
+            @Nullable Bundle extras) {
+        return mImpl.call(method, arg, extras);
+    }
+
+    @Nullable
+    @Override
+    public final Uri canonicalize(@NonNull Uri url) {
+        return mImpl.canonicalize(url);
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/compat/SliceProviderCompat.java b/slices/core/src/main/java/androidx/app/slice/compat/SliceProviderCompat.java
new file mode 100644
index 0000000..bc907da
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/compat/SliceProviderCompat.java
@@ -0,0 +1,261 @@
+/*
+ * 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.compat;
+
+import static android.app.slice.SliceProvider.SLICE_TYPE;
+
+import android.Manifest.permission;
+import android.content.ContentProvider;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Parcelable;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.StrictMode;
+import android.os.StrictMode.ThreadPolicy;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.util.Log;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceProvider;
+
+/**
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+public class SliceProviderCompat extends ContentProvider {
+
+    private static final String TAG = "SliceProvider";
+
+    public static final String EXTRA_BIND_URI = "slice_uri";
+    public static final String METHOD_SLICE = "bind_slice";
+    public static final String METHOD_MAP_INTENT = "map_slice";
+    public static final String EXTRA_INTENT = "slice_intent";
+    public static final String EXTRA_SLICE = "slice";
+
+    private static final boolean DEBUG = false;
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+    private SliceProvider mSliceProvider;
+
+    public SliceProviderCompat(SliceProvider provider) {
+        mSliceProvider = provider;
+    }
+
+    @Override
+    public boolean onCreate() {
+        return mSliceProvider.onCreateSliceProvider();
+    }
+
+    @Override
+    public final int update(Uri uri, ContentValues values, String selection,
+            String[] selectionArgs) {
+        if (DEBUG) Log.d(TAG, "update " + uri);
+        return 0;
+    }
+
+    @Override
+    public final int delete(Uri uri, String selection, String[] selectionArgs) {
+        if (DEBUG) Log.d(TAG, "delete " + uri);
+        return 0;
+    }
+
+    @Override
+    public final Cursor query(Uri uri, String[] projection, String selection,
+            String[] selectionArgs, String sortOrder) {
+        if (DEBUG) Log.d(TAG, "query " + uri);
+        return null;
+    }
+
+    @Override
+    public final Cursor query(Uri uri, String[] projection, String selection, String[]
+            selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
+        if (DEBUG) Log.d(TAG, "query " + uri);
+        return null;
+    }
+
+    @Override
+    public final Cursor query(Uri uri, String[] projection, Bundle queryArgs,
+            CancellationSignal cancellationSignal) {
+        if (DEBUG) Log.d(TAG, "query " + uri);
+        return null;
+    }
+
+    @Override
+    public final Uri insert(Uri uri, ContentValues values) {
+        if (DEBUG) Log.d(TAG, "insert " + uri);
+        return null;
+    }
+
+    @Override
+    public final String getType(Uri uri) {
+        if (DEBUG) Log.d(TAG, "getFormat " + uri);
+        return SLICE_TYPE;
+    }
+
+    @Override
+    public Bundle call(String method, String arg, Bundle extras) {
+        if (method.equals(METHOD_SLICE)) {
+            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+            if (Binder.getCallingUid() != Process.myUid()) {
+                getContext().enforceUriPermission(uri, permission.BIND_SLICE,
+                        permission.BIND_SLICE, Binder.getCallingPid(), Binder.getCallingUid(),
+                        Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+                        "Slice binding requires the permission BIND_SLICE");
+            }
+
+            Slice s = handleBindSlice(uri);
+            Bundle b = new Bundle();
+            b.putParcelable(EXTRA_SLICE, s.toBundle());
+            return b;
+        } else if (method.equals(METHOD_MAP_INTENT)) {
+            getContext().enforceCallingPermission(permission.BIND_SLICE,
+                    "Slice binding requires the permission BIND_SLICE");
+            Intent intent = extras.getParcelable(EXTRA_INTENT);
+            Uri uri = mSliceProvider.onMapIntentToUri(intent);
+            Bundle b = new Bundle();
+            if (uri != null) {
+                Slice s = handleBindSlice(uri);
+                b.putParcelable(EXTRA_SLICE, s.toBundle());
+            } else {
+                b.putParcelable(EXTRA_SLICE, null);
+            }
+            return b;
+        }
+        return super.call(method, arg, extras);
+    }
+
+    private Slice handleBindSlice(Uri sliceUri) {
+        if (Looper.myLooper() == Looper.getMainLooper()) {
+            return onBindSliceStrict(sliceUri);
+        } else {
+            CountDownLatch latch = new CountDownLatch(1);
+            Slice[] output = new Slice[1];
+            mHandler.post(() -> {
+                output[0] = onBindSliceStrict(sliceUri);
+                latch.countDown();
+            });
+            try {
+                latch.await();
+                return output[0];
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    private Slice onBindSliceStrict(Uri sliceUri) {
+        ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
+        try {
+            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
+                    .detectAll()
+                    .penaltyDeath()
+                    .build());
+            return mSliceProvider.onBindSlice(sliceUri);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
+    }
+
+    /**
+     * Compat version of {@link Slice#bindSlice(Context, Uri)}.
+     */
+    public static Slice bindSlice(Context context, Uri uri) {
+        ContentProviderClient provider = context.getContentResolver()
+                .acquireContentProviderClient(uri);
+        if (provider == null) {
+            throw new IllegalArgumentException("Unknown URI " + uri);
+        }
+        try {
+            Bundle extras = new Bundle();
+            extras.putParcelable(EXTRA_BIND_URI, uri);
+            final Bundle res = provider.call(METHOD_SLICE, null, extras);
+            if (res == null) {
+                return null;
+            }
+            Parcelable bundle = res.getParcelable(EXTRA_SLICE);
+            if (!(bundle instanceof Bundle)) {
+                return null;
+            }
+            return new Slice((Bundle) bundle);
+        } catch (RemoteException e) {
+            // Arbitrary and not worth documenting, as Activity
+            // Manager will kill this process shortly anyway.
+            return null;
+        } finally {
+            provider.close();
+        }
+    }
+
+    /**
+     * Compat version of {@link Slice#bindSlice(Context, Intent)}.
+     */
+    public static Slice bindSlice(Context context, Intent intent) {
+        ContentResolver resolver = context.getContentResolver();
+
+        // Check if the intent has data for the slice uri on it and use that
+        final Uri intentData = intent.getData();
+        if (intentData != null && SLICE_TYPE.equals(resolver.getType(intentData))) {
+            return bindSlice(context, intentData);
+        }
+        // Otherwise ask the app
+        List<ResolveInfo> providers =
+                context.getPackageManager().queryIntentContentProviders(intent, 0);
+        if (providers == null) {
+            throw new IllegalArgumentException("Unable to resolve intent " + intent);
+        }
+        String authority = providers.get(0).providerInfo.authority;
+        Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(authority).build();
+        ContentProviderClient provider = resolver.acquireContentProviderClient(uri);
+        if (provider == null) {
+            throw new IllegalArgumentException("Unknown URI " + uri);
+        }
+        try {
+            Bundle extras = new Bundle();
+            extras.putParcelable(EXTRA_INTENT, intent);
+            final Bundle res = provider.call(METHOD_MAP_INTENT, null, extras);
+            if (res == null) {
+                return null;
+            }
+            Parcelable bundle = res.getParcelable(EXTRA_SLICE);
+            if (!(bundle instanceof Bundle)) {
+                return null;
+            }
+            return new Slice((Bundle) bundle);
+        } catch (RemoteException e) {
+            // Arbitrary and not worth documenting, as Activity
+            // Manager will kill this process shortly anyway.
+            return null;
+        } finally {
+            provider.close();
+        }
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/compat/SliceProviderWrapper.java b/slices/core/src/main/java/androidx/app/slice/compat/SliceProviderWrapper.java
new file mode 100644
index 0000000..61f8eb9
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/compat/SliceProviderWrapper.java
@@ -0,0 +1,60 @@
+/*
+ * 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.compat;
+
+import android.app.slice.Slice;
+import android.app.slice.SliceProvider;
+import android.app.slice.SliceSpec;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+
+import java.util.List;
+
+import androidx.app.slice.SliceConvert;
+
+/**
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+public class SliceProviderWrapper extends SliceProvider {
+
+    private androidx.app.slice.SliceProvider mSliceProvider;
+
+    public SliceProviderWrapper(androidx.app.slice.SliceProvider provider) {
+        mSliceProvider = provider;
+    }
+
+    @Override
+    public boolean onCreate() {
+        return mSliceProvider.onCreateSliceProvider();
+    }
+
+    @Override
+    public Slice onBindSlice(Uri sliceUri, List<SliceSpec> supportedVersions) {
+        return SliceConvert.unwrap(mSliceProvider.onBindSlice(sliceUri));
+    }
+
+    /**
+     * Maps intents to uris.
+     */
+    @Override
+    public @NonNull Uri onMapIntentToUri(Intent intent) {
+        return mSliceProvider.onMapIntentToUri(intent);
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/core/SliceQuery.java b/slices/core/src/main/java/androidx/app/slice/core/SliceQuery.java
index eec898e..5f87126 100644
--- a/slices/core/src/main/java/androidx/app/slice/core/SliceQuery.java
+++ b/slices/core/src/main/java/androidx/app/slice/core/SliceQuery.java
@@ -16,14 +16,15 @@
 
 package androidx.app.slice.core;
 
+import static android.app.slice.Slice.HINT_ACTIONS;
+import static android.app.slice.Slice.HINT_LIST;
+import static android.app.slice.Slice.HINT_LIST_ITEM;
 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_SLICE;
 import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
 
-import android.app.slice.Slice;
-import android.app.slice.SliceItem;
 import android.support.annotation.RestrictTo;
 import android.text.TextUtils;
 
@@ -36,6 +37,9 @@
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
+
 /**
  * Utilities for finding content within a Slice.
  * @hide
@@ -143,9 +147,9 @@
             if (FORMAT_IMAGE.equals(item.getFormat())) {
                 return item;
             }
-            if (!(FORMAT_SLICE.equals(item.getFormat()) && item.hasHint(Slice.HINT_LIST))
-                    && !item.hasHint(Slice.HINT_ACTIONS)
-                    && !item.hasHint(Slice.HINT_LIST_ITEM)
+            if (!(FORMAT_SLICE.equals(item.getFormat()) && item.hasHint(HINT_LIST))
+                    && !item.hasHint(HINT_ACTIONS)
+                    && !item.hasHint(HINT_LIST_ITEM)
                     && !FORMAT_ACTION.equals(item.getFormat())) {
                 SliceItem icon = SliceQuery.find(item, FORMAT_IMAGE);
                 if (icon != null) {
diff --git a/slices/core/src/main/res-public/values-v28/strings.xml b/slices/core/src/main/res-public/values-v28/strings.xml
new file mode 100644
index 0000000..12dabc6
--- /dev/null
+++ b/slices/core/src/main/res-public/values-v28/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="slice_provider">androidx.app.slice.compat.SliceProviderWrapper</string>
+</resources>
\ No newline at end of file
diff --git a/slices/core/src/main/res-public/values/strings.xml b/slices/core/src/main/res-public/values/strings.xml
new file mode 100644
index 0000000..d492a38
--- /dev/null
+++ b/slices/core/src/main/res-public/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="slice_provider">androidx.app.slice.compat.SliceProviderCompat</string>
+</resources>
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/ActionRow.java b/slices/view/src/main/java/androidx/app/slice/widget/ActionRow.java
index c38088c..a38441f 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/ActionRow.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/ActionRow.java
@@ -16,6 +16,7 @@
 
 package androidx.app.slice.widget;
 
+import static android.app.slice.Slice.HINT_NO_TINT;
 import static android.app.slice.SliceItem.FORMAT_ACTION;
 import static android.app.slice.SliceItem.FORMAT_COLOR;
 import static android.app.slice.SliceItem.FORMAT_IMAGE;
@@ -24,8 +25,6 @@
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
 import android.app.RemoteInput;
-import android.app.slice.Slice;
-import android.app.slice.SliceItem;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Color;
@@ -41,6 +40,7 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.app.slice.SliceItem;
 import androidx.app.slice.core.SliceQuery;
 
 /**
@@ -75,7 +75,7 @@
         for (int i = 0; i < mActionsGroup.getChildCount(); i++) {
             View view = mActionsGroup.getChildAt(i);
             SliceItem item = (SliceItem) view.getTag();
-            boolean tint = !item.hasHint(Slice.HINT_NO_TINT);
+            boolean tint = !item.hasHint(HINT_NO_TINT);
             if (tint) {
                 ((ImageView) view).setImageTintList(ColorStateList.valueOf(mColor));
             }
@@ -120,7 +120,7 @@
             if (image == null) {
                 return;
             }
-            boolean tint = !image.hasHint(Slice.HINT_NO_TINT);
+            boolean tint = !image.hasHint(HINT_NO_TINT);
             SliceItem input = SliceQuery.find(action, FORMAT_REMOTE_INPUT);
             if (input != null && input.getRemoteInput().getAllowFreeFormInput()) {
                 addAction(image.getIcon(), tint, image).setOnClickListener(
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/GridView.java b/slices/view/src/main/java/androidx/app/slice/widget/GridView.java
index 9fa8a5d..231f90a 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/GridView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/GridView.java
@@ -16,6 +16,8 @@
 
 package androidx.app.slice.widget;
 
+import static android.app.slice.Slice.HINT_LARGE;
+import static android.app.slice.Slice.HINT_TITLE;
 import static android.app.slice.SliceItem.FORMAT_COLOR;
 import static android.app.slice.SliceItem.FORMAT_IMAGE;
 import static android.app.slice.SliceItem.FORMAT_SLICE;
@@ -23,8 +25,6 @@
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
-import android.app.slice.Slice;
-import android.app.slice.SliceItem;
 import android.content.Context;
 import android.graphics.Color;
 import android.support.annotation.RestrictTo;
@@ -42,6 +42,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import androidx.app.slice.SliceItem;
 import androidx.app.slice.core.SliceQuery;
 import androidx.app.slice.view.R;
 
@@ -155,7 +156,7 @@
                     case FORMAT_TEXT:
                         boolean title = false;
                         if ((SliceQuery.hasAnyHints(item, new String[] {
-                                Slice.HINT_LARGE, Slice.HINT_TITLE
+                                HINT_LARGE, HINT_TITLE
                         }))) {
                             title = true;
                         }
@@ -168,7 +169,7 @@
                     case FORMAT_IMAGE:
                         ImageView iv = new ImageView(context);
                         iv.setImageIcon(i.getIcon());
-                        if (item.hasHint(Slice.HINT_LARGE)) {
+                        if (item.hasHint(HINT_LARGE)) {
                             iv.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
                         } else {
                             int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/LargeSliceAdapter.java b/slices/view/src/main/java/androidx/app/slice/widget/LargeSliceAdapter.java
index 11928fd..bb1fc17 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/LargeSliceAdapter.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/LargeSliceAdapter.java
@@ -16,14 +16,13 @@
 
 package androidx.app.slice.widget;
 
+import static android.app.slice.Slice.HINT_HORIZONTAL;
 import static android.app.slice.Slice.SUBTYPE_MESSAGE;
 import static android.app.slice.Slice.SUBTYPE_SOURCE;
 import static android.app.slice.SliceItem.FORMAT_COLOR;
 import static android.app.slice.SliceItem.FORMAT_IMAGE;
 import static android.app.slice.SliceItem.FORMAT_TEXT;
 
-import android.app.slice.Slice;
-import android.app.slice.SliceItem;
 import android.content.Context;
 import android.support.annotation.RestrictTo;
 import android.support.v7.widget.RecyclerView;
@@ -37,6 +36,7 @@
 import java.util.List;
 import java.util.stream.Collectors;
 
+import androidx.app.slice.SliceItem;
 import androidx.app.slice.core.SliceQuery;
 import androidx.app.slice.view.R;
 
@@ -137,7 +137,7 @@
                     return TYPE_MESSAGE_LOCAL;
                 }
             }
-            if (item.hasHint(Slice.HINT_HORIZONTAL)) {
+            if (item.hasHint(HINT_HORIZONTAL)) {
                 return TYPE_GRID;
             }
             return TYPE_DEFAULT;
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java b/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
index c59b056..0188c21 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
@@ -16,12 +16,14 @@
 
 package androidx.app.slice.widget;
 
+import static android.app.slice.Slice.HINT_ACTIONS;
+import static android.app.slice.Slice.HINT_LIST;
+import static android.app.slice.Slice.HINT_LIST_ITEM;
+import static android.app.slice.Slice.HINT_PARTIAL;
 import static android.app.slice.SliceItem.FORMAT_COLOR;
 import static android.app.slice.SliceItem.FORMAT_SLICE;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
-import android.app.slice.Slice;
-import android.app.slice.SliceItem;
 import android.content.Context;
 import android.support.annotation.RestrictTo;
 import android.support.v7.widget.LinearLayoutManager;
@@ -31,6 +33,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
 import androidx.app.slice.core.SliceQuery;
 
 /**
@@ -70,7 +74,7 @@
         mRecyclerView.getLayoutParams().height = WRAP_CONTENT;
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         if (mRecyclerView.getMeasuredHeight() > mMaxHeight
-                || (mSlice != null && SliceQuery.hasHints(mSlice, Slice.HINT_PARTIAL))) {
+                || (mSlice != null && SliceQuery.hasHints(mSlice, HINT_PARTIAL))) {
             mRecyclerView.getLayoutParams().height = mDefaultHeight;
         } else {
             mRecyclerView.getLayoutParams().height = mRecyclerView.getMeasuredHeight();
@@ -84,18 +88,18 @@
         mSlice = slice;
         List<SliceItem> items = new ArrayList<>();
         boolean[] hasHeader = new boolean[1];
-        if (SliceQuery.hasHints(slice, Slice.HINT_LIST)) {
+        if (SliceQuery.hasHints(slice, HINT_LIST)) {
             addList(slice, items);
         } else {
             slice.getItems().forEach(item -> {
-                if (item.hasHint(Slice.HINT_ACTIONS)) {
+                if (item.hasHint(HINT_ACTIONS)) {
                     return;
                 } else if (FORMAT_COLOR.equals(item.getFormat())) {
                     return;
                 } else if (FORMAT_SLICE.equals(item.getFormat())
-                        && item.hasHint(Slice.HINT_LIST)) {
+                        && item.hasHint(HINT_LIST)) {
                     addList(item.getSlice(), items);
-                } else if (item.hasHint(Slice.HINT_LIST_ITEM)) {
+                } else if (item.hasHint(HINT_LIST_ITEM)) {
                     items.add(item);
                 } else if (!hasHeader[0]) {
                     hasHeader[0] = true;
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/MessageView.java b/slices/view/src/main/java/androidx/app/slice/widget/MessageView.java
index a7ccd36..5611f05 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/MessageView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/MessageView.java
@@ -16,11 +16,11 @@
 
 package androidx.app.slice.widget;
 
+import static android.app.slice.Slice.SUBTYPE_SOURCE;
 import static android.app.slice.SliceItem.FORMAT_IMAGE;
 import static android.app.slice.SliceItem.FORMAT_TEXT;
 
-import android.app.slice.Slice;
-import android.app.slice.SliceItem;
+
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -33,6 +33,7 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.app.slice.SliceItem;
 import androidx.app.slice.core.SliceQuery;
 
 /**
@@ -57,7 +58,7 @@
 
     @Override
     public void setSliceItem(SliceItem slice) {
-        SliceItem source = SliceQuery.findSubtype(slice, FORMAT_IMAGE, Slice.SUBTYPE_SOURCE);
+        SliceItem source = SliceQuery.findSubtype(slice, FORMAT_IMAGE, SUBTYPE_SOURCE);
         if (source != null) {
             final int iconSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                     24, getContext().getResources().getDisplayMetrics());
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/ShortcutView.java b/slices/view/src/main/java/androidx/app/slice/widget/ShortcutView.java
index 136d0ff..e553653 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/ShortcutView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/ShortcutView.java
@@ -16,6 +16,8 @@
 
 package androidx.app.slice.widget;
 
+import static android.app.slice.Slice.HINT_LARGE;
+import static android.app.slice.Slice.HINT_TITLE;
 import static android.app.slice.Slice.SUBTYPE_SOURCE;
 import static android.app.slice.SliceItem.FORMAT_ACTION;
 import static android.app.slice.SliceItem.FORMAT_COLOR;
@@ -24,8 +26,6 @@
 
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
-import android.app.slice.Slice;
-import android.app.slice.SliceItem;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -39,6 +39,8 @@
 import android.net.Uri;
 import android.support.annotation.RestrictTo;
 
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
 import androidx.app.slice.core.SliceQuery;
 import androidx.app.slice.view.R;
 
@@ -79,7 +81,7 @@
         circle.setTint(color);
         setBackground(circle);
         if (mIcon != null) {
-            final boolean isLarge = mIcon.hasHint(Slice.HINT_LARGE)
+            final boolean isLarge = mIcon.hasHint(HINT_LARGE)
                     || SUBTYPE_SOURCE.equals(mIcon.getSubType());
             final int iconSize = isLarge ? mLargeIconSize : mSmallIconSize;
             SliceViewUtil.createCircledIcon(getContext(), color, iconSize, mIcon.getIcon(),
@@ -119,14 +121,14 @@
      */
     private void determineShortcutItems(Context context, Slice slice) {
         SliceItem titleItem = SliceQuery.find(slice, FORMAT_ACTION,
-                Slice.HINT_TITLE, null);
+                HINT_TITLE, null);
 
         if (titleItem != null) {
             // Preferred case: hinted action containing hinted image and text
             mAction = titleItem.getAction();
-            mIcon = SliceQuery.find(titleItem.getSlice(), FORMAT_IMAGE, Slice.HINT_TITLE,
+            mIcon = SliceQuery.find(titleItem.getSlice(), FORMAT_IMAGE, HINT_TITLE,
                     null);
-            mLabel = SliceQuery.find(titleItem.getSlice(), FORMAT_TEXT, Slice.HINT_TITLE,
+            mLabel = SliceQuery.find(titleItem.getSlice(), FORMAT_TEXT, HINT_TITLE,
                     null);
         } else {
             // No hinted action; just use the first one
@@ -136,11 +138,11 @@
         }
         // First fallback: any hinted image and text
         if (mIcon == null) {
-            mIcon = SliceQuery.find(slice, FORMAT_IMAGE, Slice.HINT_TITLE,
+            mIcon = SliceQuery.find(slice, FORMAT_IMAGE, HINT_TITLE,
                     null);
         }
         if (mLabel == null) {
-            mLabel = SliceQuery.find(slice, FORMAT_TEXT, Slice.HINT_TITLE,
+            mLabel = SliceQuery.find(slice, FORMAT_TEXT, HINT_TITLE,
                     null);
         }
         // Second fallback: first image and text
@@ -162,7 +164,7 @@
                 if (mIcon == null) {
                     Slice.Builder sb = new Slice.Builder(slice.getUri());
                     Drawable icon = pm.getApplicationIcon(appInfo);
-                    sb.addIcon(SliceViewUtil.createIconFromDrawable(icon), Slice.HINT_LARGE);
+                    sb.addIcon(SliceViewUtil.createIconFromDrawable(icon), HINT_LARGE);
                     mIcon = sb.build().getItems().get(0);
                 }
                 if (mLabel == null) {
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/SliceLiveData.java b/slices/view/src/main/java/androidx/app/slice/widget/SliceLiveData.java
index b0c0139..458aa83 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/SliceLiveData.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/SliceLiveData.java
@@ -15,7 +15,6 @@
  */
 package androidx.app.slice.widget;
 
-import android.app.slice.Slice;
 import android.arch.lifecycle.LiveData;
 import android.content.Context;
 import android.database.ContentObserver;
@@ -23,7 +22,7 @@
 import android.os.AsyncTask;
 import android.os.Handler;
 
-import androidx.app.slice.core.SliceSpecs;
+import androidx.app.slice.Slice;
 
 /**
  * Class with factory methods for creating LiveData that observes slices.
@@ -65,8 +64,7 @@
         }
 
         private void updateSlice() {
-            postValue(Slice.bindSlice(mContext.getContentResolver(), mUri,
-                    SliceSpecs.SUPPORTED_SPECS));
+            postValue(Slice.bindSlice(mContext, mUri));
         }
 
         private final ContentObserver mObserver = new ContentObserver(new Handler()) {
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java b/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
index df63be9..306f0af 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
@@ -16,11 +16,10 @@
 
 package androidx.app.slice.widget;
 
+import static android.app.slice.Slice.HINT_ACTIONS;
 import static android.app.slice.SliceItem.FORMAT_COLOR;
 import static android.app.slice.SliceItem.FORMAT_SLICE;
 
-import android.app.slice.Slice;
-import android.app.slice.SliceItem;
 import android.arch.lifecycle.Observer;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -37,6 +36,8 @@
 
 import java.util.List;
 
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
 import androidx.app.slice.core.SliceQuery;
 import androidx.app.slice.view.R;
 
@@ -57,8 +58,9 @@
  * <p>
  * When constructing a slice, the contents of it can be annotated with hints, these provide the OS
  * with some information on how the content should be displayed. For example, text annotated with
- * {@link Slice#HINT_TITLE} would be placed in the title position of a template. A slice annotated
- * with {@link Slice#HINT_LIST} would present the child items of that slice in a list.
+ * {@link android.app.slice.Slice#HINT_TITLE} would be placed in the title position of a template.
+ * A slice annotated with {@link android.app.slice.Slice#HINT_LIST} would present the child items
+ * of that slice in a list.
  * <p>
  * Example usage:
  *
@@ -114,8 +116,8 @@
     public static final int MODE_LARGE       = 2;
     /**
      * Mode indicating this slice should be presented as an icon. A shortcut requires an intent,
-     * icon, and label. This can be indicated by using {@link Slice#HINT_TITLE} on an action in a
-     * slice.
+     * icon, and label. This can be indicated by using {@link android.app.slice.Slice#HINT_TITLE}
+     * on an action in a slice.
      */
     public static final int MODE_SHORTCUT    = 3;
 
@@ -267,7 +269,7 @@
         SliceItem color = SliceQuery.find(mCurrentSlice, FORMAT_COLOR);
         List<SliceItem> items = mCurrentSlice.getItems();
         SliceItem actionRow = SliceQuery.find(mCurrentSlice, FORMAT_SLICE,
-                Slice.HINT_ACTIONS,
+                HINT_ACTIONS,
                 null);
         int mode = getMode();
         if (mode != mCurrentView.getMode()) {
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/SmallTemplateView.java b/slices/view/src/main/java/androidx/app/slice/widget/SmallTemplateView.java
index d20c096..1a94e0a 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/SmallTemplateView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/SmallTemplateView.java
@@ -16,6 +16,11 @@
 
 package androidx.app.slice.widget;
 
+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_SELECTED;
+import static android.app.slice.Slice.HINT_TITLE;
 import static android.app.slice.SliceItem.FORMAT_ACTION;
 import static android.app.slice.SliceItem.FORMAT_COLOR;
 import static android.app.slice.SliceItem.FORMAT_IMAGE;
@@ -25,8 +30,6 @@
 
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
-import android.app.slice.Slice;
-import android.app.slice.SliceItem;
 import android.content.Context;
 import android.content.Intent;
 import android.os.AsyncTask;
@@ -41,6 +44,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
 import androidx.app.slice.core.SliceHints;
 import androidx.app.slice.core.SliceQuery;
 import androidx.app.slice.view.R;
@@ -116,12 +121,12 @@
         if (items.size() > 0 && FORMAT_SLICE.equals(items.get(0).getFormat())) {
             // Check if this slice is appropriate to use to populate small template
             SliceItem firstSlice = items.get(0);
-            if (firstSlice.hasHint(Slice.HINT_LIST)) {
+            if (firstSlice.hasHint(HINT_LIST)) {
                 // Check for header, use that if it exists
                 SliceItem header = SliceQuery.find(firstSlice, FORMAT_SLICE,
                         null,
                         new String[] {
-                                Slice.HINT_LIST_ITEM, Slice.HINT_LIST
+                                HINT_LIST_ITEM, HINT_LIST
                         });
                 if (header != null) {
                     return SliceQuery.findFirstSlice(header);
@@ -176,12 +181,12 @@
             SliceItem item = items.get(i);
             List<String> hints = item.getHints();
             String itemType = item.getFormat();
-            if (hints.contains(Slice.HINT_TITLE)) {
+            if (hints.contains(HINT_TITLE)) {
                 // Things with these hints could go in the title / start position
-                if ((startItem == null || !startItem.hasHint(Slice.HINT_TITLE))
+                if ((startItem == null || !startItem.hasHint(HINT_TITLE))
                         && SliceQuery.isStartType(item)) {
                     startItem = item;
-                } else if ((titleItem == null || !titleItem.hasHint(Slice.HINT_TITLE))
+                } else if ((titleItem == null || !titleItem.hasHint(HINT_TITLE))
                         && FORMAT_TEXT.equals(itemType)) {
                     titleItem = item;
                 } else {
@@ -287,7 +292,7 @@
         }
         mToggle = new Switch(getContext());
         mEndContainer.addView(mToggle);
-        mToggle.setChecked(SliceQuery.hasHints(toggleItem.getSlice(), Slice.HINT_SELECTED));
+        mToggle.setChecked(SliceQuery.hasHints(toggleItem.getSlice(), HINT_SELECTED));
         mToggle.setOnCheckedChangeListener((buttonView, isChecked) -> {
             try {
                 PendingIntent pi = toggleItem.getAction();
@@ -328,7 +333,7 @@
                 iv.setBackground(SliceViewUtil.getDrawable(getContext(),
                         android.R.attr.selectableItemBackground));
             }
-            if (color != -1 && !sliceItem.hasHint(Slice.HINT_NO_TINT)) {
+            if (color != -1 && !sliceItem.hasHint(HINT_NO_TINT)) {
                 iv.setColorFilter(color);
             }
             container.addView(iv);