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

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

Merge changes from topics "SliceDesc", "SliceCleanup"

* changes:
  Add SliceManager#getSliceDescendants
  Update slice APIs
parents d8b49d39 5f8cc27e
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -7068,8 +7068,8 @@ 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, java.util.List<android.app.slice.SliceSpec>);
    method public static android.app.slice.Slice bindSlice(android.content.Context, android.content.Intent, java.util.List<android.app.slice.SliceSpec>);
    method public static deprecated android.app.slice.Slice bindSlice(android.content.ContentResolver, android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
    method public static deprecated android.app.slice.Slice bindSlice(android.content.Context, android.content.Intent, java.util.List<android.app.slice.SliceSpec>);
    method public int describeContents();
    method public java.util.List<java.lang.String> getHints();
    method public java.util.List<android.app.slice.SliceItem> getItems();
@@ -7155,7 +7155,10 @@ package android.app.slice {
  }
  public class SliceManager {
    method public android.app.slice.Slice bindSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
    method public android.app.slice.Slice bindSlice(android.content.Intent, java.util.List<android.app.slice.SliceSpec>);
    method public java.util.List<android.app.slice.SliceSpec> getPinnedSpecs(android.net.Uri);
    method public java.util.Collection<android.net.Uri> getSliceDescendants(android.net.Uri);
    method public void pinSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
    method public void registerSliceCallback(android.net.Uri, android.app.slice.SliceManager.SliceCallback, java.util.List<android.app.slice.SliceSpec>);
    method public void registerSliceCallback(android.net.Uri, android.app.slice.SliceManager.SliceCallback, java.util.List<android.app.slice.SliceSpec>, android.os.Handler);
@@ -7174,7 +7177,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 android.app.slice.Slice onBindSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
    method public deprecated android.app.slice.Slice onBindSlice(android.net.Uri);
    method public java.util.Collection<android.net.Uri> onGetSliceDescendants(android.net.Uri);
    method public android.net.Uri onMapIntentToUri(android.content.Intent);
    method public void onSlicePinned(android.net.Uri);
    method public void onSliceUnpinned(android.net.Uri);
+9 −65
Original line number Diff line number Diff line
@@ -21,12 +21,10 @@ import android.annotation.Nullable;
import android.annotation.StringDef;
import android.app.PendingIntent;
import android.app.RemoteInput;
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;
@@ -553,16 +551,11 @@ public final class Slice implements Parcelable {
    }

    /**
     * Turns a slice Uri into slice content.
     *
     * @param resolver ContentResolver to be used.
     * @param uri The URI to a slice provider
     * @param supportedSpecs List of supported specs.
     * @return The Slice provided by the app or null if none is given.
     * @see Slice
     */
    public static @Nullable Slice bindSlice(ContentResolver resolver, @NonNull Uri uri,
            List<SliceSpec> supportedSpecs) {
     * @deprecated TO BE REMOVED.
     */
    @Deprecated
    public static @Nullable Slice bindSlice(ContentResolver resolver,
            @NonNull Uri uri, @NonNull List<SliceSpec> supportedSpecs) {
        Preconditions.checkNotNull(uri, "uri");
        IContentProvider provider = resolver.acquireProvider(uri);
        if (provider == null) {
@@ -590,60 +583,11 @@ public final class Slice implements Parcelable {
    }

    /**
     * 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.
     * @param supportedSpecs List of supported specs.
     * @return The Slice provided by the app or null if none is given.
     * @see Slice
     * @see SliceProvider#onMapIntentToUri(Intent)
     * @see Intent
     * @deprecated TO BE REMOVED.
     */
    @Deprecated
    public static @Nullable Slice bindSlice(Context context, @NonNull Intent intent,
            List<SliceSpec> supportedSpecs) {
        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, supportedSpecs);
        }
        // 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);
            extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
                    new ArrayList<>(supportedSpecs));
            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);
        }
            @NonNull List<SliceSpec> supportedSpecs) {
        return context.getSystemService(SliceManager.class).bindSlice(intent, supportedSpecs);
    }
}
+134 −0
Original line number Diff line number Diff line
@@ -17,17 +17,29 @@
package android.app.slice;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IContentProvider;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;

import com.android.internal.util.Preconditions;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;

@@ -39,6 +51,8 @@ import java.util.concurrent.Executor;
@SystemService(Context.SLICE_SERVICE)
public class SliceManager {

    private static final String TAG = "SliceManager";

    private final ISliceManager mService;
    private final Context mContext;
    private final ArrayMap<Pair<Uri, SliceCallback>, ISliceListener> mListenerLookup =
@@ -223,6 +237,126 @@ public class SliceManager {
        }
    }

    /**
     * Obtains a list of slices that are descendants of the specified Uri.
     * <p>
     * Not all slice providers will implement this functionality, in which case,
     * an empty collection will be returned.
     *
     * @param uri The uri to look for descendants under.
     * @return All slices within the space.
     * @see SliceProvider#onGetSliceDescendants(Uri)
     */
    public @NonNull Collection<Uri> getSliceDescendants(@NonNull Uri uri) {
        ContentResolver resolver = mContext.getContentResolver();
        IContentProvider provider = resolver.acquireProvider(uri);
        try {
            Bundle extras = new Bundle();
            extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
            final Bundle res = provider.call(resolver.getPackageName(),
                    SliceProvider.METHOD_GET_DESCENDANTS, null, extras);
            return res.getParcelableArrayList(SliceProvider.EXTRA_SLICE_DESCENDANTS);
        } catch (RemoteException e) {
            Log.e(TAG, "Unable to get slice descendants", e);
        } finally {
            resolver.releaseProvider(provider);
        }
        return Collections.emptyList();
    }

    /**
     * Turns a slice Uri into slice content.
     *
     * @param uri The URI to a slice provider
     * @param supportedSpecs List of supported specs.
     * @return The Slice provided by the app or null if none is given.
     * @see Slice
     */
    public @Nullable Slice bindSlice(@NonNull Uri uri, @NonNull List<SliceSpec> supportedSpecs) {
        Preconditions.checkNotNull(uri, "uri");
        ContentResolver resolver = mContext.getContentResolver();
        IContentProvider provider = resolver.acquireProvider(uri);
        if (provider == null) {
            throw new IllegalArgumentException("Unknown URI " + uri);
        }
        try {
            Bundle extras = new Bundle();
            extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
            extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
                    new ArrayList<>(supportedSpecs));
            final Bundle res = provider.call(resolver.getPackageName(), SliceProvider.METHOD_SLICE,
                    null, extras);
            Bundle.setDefusable(res, true);
            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);
        }
    }

    /**
     * Turns a slice intent into slice content. Expects an explicit intent. If there is no
     * {@link android.content.ContentProvider} associated with the given intent this will throw
     * {@link IllegalArgumentException}.
     *
     * @param intent The intent associated with a slice.
     * @param supportedSpecs List of supported specs.
     * @return The Slice provided by the app or null if none is given.
     * @see Slice
     * @see SliceProvider#onMapIntentToUri(Intent)
     * @see Intent
     */
    public @Nullable Slice bindSlice(@NonNull Intent intent,
            @NonNull List<SliceSpec> supportedSpecs) {
        Preconditions.checkNotNull(intent, "intent");
        Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null,
                "Slice intent must be explicit " + intent);
        ContentResolver resolver = mContext.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(intentData, supportedSpecs);
        }
        // Otherwise ask the app
        List<ResolveInfo> providers =
                mContext.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);
            extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
                    new ArrayList<>(supportedSpecs));
            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);
        }
    }

    /**
     * Class that listens to changes in {@link Slice}s.
     */
+50 −8
Original line number Diff line number Diff line
@@ -36,6 +36,9 @@ import android.os.StrictMode.ThreadPolicy;
import android.os.UserHandle;
import android.util.Log;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

@@ -110,6 +113,10 @@ public abstract class SliceProvider extends ContentProvider {
     * @hide
     */
    public static final String METHOD_UNPIN = "unpin";
    /**
     * @hide
     */
    public static final String METHOD_GET_DESCENDANTS = "get_descendants";
    /**
     * @hide
     */
@@ -118,6 +125,10 @@ public abstract class SliceProvider extends ContentProvider {
     * @hide
     */
    public static final String EXTRA_SLICE = "slice";
    /**
     * @hide
     */
    public static final String EXTRA_SLICE_DESCENDANTS = "slice_descendants";

    private static final boolean DEBUG = false;

@@ -139,14 +150,6 @@ public abstract class SliceProvider extends ContentProvider {
     * @see {@link Slice#HINT_PARTIAL}
     */
    public Slice onBindSlice(Uri sliceUri, List<SliceSpec> supportedSpecs) {
        return onBindSlice(sliceUri);
    }

    /**
     * @deprecated migrating to {@link #onBindSlice(Uri, List)}
     */
    @Deprecated
    public Slice onBindSlice(Uri sliceUri) {
        return null;
    }

@@ -182,6 +185,20 @@ public abstract class SliceProvider extends ContentProvider {
    public void onSliceUnpinned(Uri sliceUri) {
    }

    /**
     * Obtains a list of slices that are descendants of the specified Uri.
     * <p>
     * Implementing this is optional for a SliceProvider, but does provide a good
     * discovery mechanism for finding slice Uris.
     *
     * @param uri The uri to look for descendants under.
     * @return All slices within the space.
     * @see SliceManager#getSliceDescendants(Uri)
     */
    public @NonNull Collection<Uri> onGetSliceDescendants(@NonNull Uri uri) {
        return Collections.emptyList();
    }

    /**
     * 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
@@ -290,10 +307,35 @@ public abstract class SliceProvider extends ContentProvider {
                        "Slice binding requires the permission BIND_SLICE");
            }
            handleUnpinSlice(uri);
        } else if (method.equals(METHOD_GET_DESCENDANTS)) {
            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
            Bundle b = new Bundle();
            b.putParcelableArrayList(EXTRA_SLICE_DESCENDANTS,
                    new ArrayList<>(handleGetDescendants(uri)));
            return b;
        }
        return super.call(method, arg, extras);
    }

    private Collection<Uri> handleGetDescendants(Uri uri) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            return onGetSliceDescendants(uri);
        } else {
            CountDownLatch latch = new CountDownLatch(1);
            Collection<Uri>[] output = new Collection[1];
            Handler.getMain().post(() -> {
                output[0] = onGetSliceDescendants(uri);
                latch.countDown();
            });
            try {
                latch.await();
                return output[0];
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private void handlePinSlice(Uri sliceUri) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            onSlicePinned(sliceUri);