Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d28796d3 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Implement intent to uri mapping for slices"

parents 4f18c6c7 3b0a72f0
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -6974,6 +6974,7 @@ package android.app.slice {
  public final class Slice implements android.os.Parcelable {
    ctor protected Slice(android.os.Parcel);
    method public static android.app.slice.Slice bindSlice(android.content.ContentResolver, android.net.Uri);
    method public static android.app.slice.Slice bindSlice(android.content.Context, android.content.Intent);
    method public int describeContents();
    method public java.util.List<java.lang.String> getHints();
    method public java.util.List<android.app.slice.SliceItem> getItems();
@@ -7042,6 +7043,7 @@ package android.app.slice {
    method public final java.lang.String getType(android.net.Uri);
    method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
    method public abstract android.app.slice.Slice onBindSlice(android.net.Uri);
    method public android.net.Uri onMapIntentToUri(android.content.Intent);
    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
+2 −0
Original line number Diff line number Diff line
@@ -7418,6 +7418,7 @@ package android.app.slice {
  public final class Slice implements android.os.Parcelable {
    ctor protected Slice(android.os.Parcel);
    method public static android.app.slice.Slice bindSlice(android.content.ContentResolver, android.net.Uri);
    method public static android.app.slice.Slice bindSlice(android.content.Context, android.content.Intent);
    method public int describeContents();
    method public java.util.List<java.lang.String> getHints();
    method public java.util.List<android.app.slice.SliceItem> getItems();
@@ -7486,6 +7487,7 @@ package android.app.slice {
    method public final java.lang.String getType(android.net.Uri);
    method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
    method public abstract android.app.slice.Slice onBindSlice(android.net.Uri);
    method public android.net.Uri onMapIntentToUri(android.content.Intent);
    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
+2 −0
Original line number Diff line number Diff line
@@ -7048,6 +7048,7 @@ package android.app.slice {
  public final class Slice implements android.os.Parcelable {
    ctor protected Slice(android.os.Parcel);
    method public static android.app.slice.Slice bindSlice(android.content.ContentResolver, android.net.Uri);
    method public static android.app.slice.Slice bindSlice(android.content.Context, android.content.Intent);
    method public int describeContents();
    method public java.util.List<java.lang.String> getHints();
    method public java.util.List<android.app.slice.SliceItem> getItems();
@@ -7116,6 +7117,7 @@ package android.app.slice {
    method public final java.lang.String getType(android.net.Uri);
    method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
    method public abstract android.app.slice.Slice onBindSlice(android.net.Uri);
    method public android.net.Uri onMapIntentToUri(android.content.Intent);
    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
+58 −1
Original line number Diff line number Diff line
@@ -21,9 +21,12 @@ import android.annotation.Nullable;
import android.annotation.StringDef;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.app.slice.widget.SliceView;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IContentProvider;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
@@ -424,4 +427,58 @@ public final class Slice implements Parcelable {
            resolver.releaseProvider(provider);
        }
    }

    /**
     * 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) {
        Preconditions.checkNotNull(intent, "intent");
        Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null,
                "Slice intent must be explicit " + 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 && SliceProvider.SLICE_TYPE.equals(resolver.getType(intentData))) {
            return bindSlice(resolver, 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();
        IContentProvider provider = resolver.acquireProvider(uri);
        if (provider == null) {
            throw new IllegalArgumentException("Unknown URI " + uri);
        }
        try {
            Bundle extras = new Bundle();
            extras.putParcelable(SliceProvider.EXTRA_INTENT, intent);
            final Bundle res = provider.call(resolver.getPackageName(),
                    SliceProvider.METHOD_MAP_INTENT, null, extras);
            if (res == null) {
                return null;
            }
            return res.getParcelable(SliceProvider.EXTRA_SLICE);
        } catch (RemoteException e) {
            // Arbitrary and not worth documenting, as Activity
            // Manager will kill this process shortly anyway.
            return null;
        } finally {
            resolver.releaseProvider(provider);
        }
    }
}
+66 −12
Original line number Diff line number Diff line
@@ -16,10 +16,13 @@
package android.app.slice;

import android.Manifest.permission;
import android.annotation.NonNull;
import android.app.slice.widget.SliceView;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
@@ -37,29 +40,45 @@ import android.util.Log;
import java.util.concurrent.CountDownLatch;

/**
 * A SliceProvider allows 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>
 * 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>
 *
 * <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 Slice
 */
public abstract class SliceProvider extends ContentProvider {

    /**
     * This is the Android platform's MIME type for a slice: URI
     * containing a slice implemented through {@link SliceProvider}.
@@ -75,6 +94,14 @@ public abstract class SliceProvider extends ContentProvider {
     * @hide
     */
    public static final String METHOD_SLICE = "bind_slice";
    /**
     * @hide
     */
    public static final String METHOD_MAP_INTENT = "map_slice";
    /**
     * @hide
     */
    public static final String EXTRA_INTENT = "slice_intent";
    /**
     * @hide
     */
@@ -98,6 +125,20 @@ public abstract class SliceProvider extends ContentProvider {
    // 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 Slice}
     * @see {@link SliceView#setSlice(Intent)}
     */
    public @NonNull Uri onMapIntentToUri(Intent intent) {
        throw new UnsupportedOperationException(
                "This provider has not implemented intent to uri mapping");
    }

    @Override
    public final int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
@@ -159,6 +200,19 @@ public abstract class SliceProvider extends ContentProvider {
            Bundle b = new Bundle();
            b.putParcelable(EXTRA_SLICE, s);
            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 = onMapIntentToUri(intent);
            Bundle b = new Bundle();
            if (uri != null) {
                Slice s = handleBindSlice(uri);
                b.putParcelable(EXTRA_SLICE, s);
            } else {
                b.putParcelable(EXTRA_SLICE, null);
            }
            return b;
        }
        return super.call(method, arg, extras);
    }
Loading