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

Commit bbd711c2 authored by Ben Lin's avatar Ben Lin Committed by Android (Google) Code Review
Browse files

Merge "Adding ContentProvider#refresh and ContentResolver#refresh."

parents bb9a5ee0 1cf454fc
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.os.ICancellationSignal;
import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
@@ -463,6 +464,23 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
            }
        }

        @Override
        public boolean refresh(String callingPkg, Uri uri, Bundle args,
                ICancellationSignal cancellationSignal) throws RemoteException {
            validateIncomingUri(uri);
            uri = getUriWithoutUserId(uri);
            if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                return false;
            }
            final String original = setCallingPackage(callingPkg);
            try {
                return ContentProvider.this.refresh(uri, args,
                        CancellationSignal.fromTransport(cancellationSignal));
            } finally {
                setCallingPackage(original);
            }
        }

        private void enforceFilePermission(String callingPkg, Uri uri, String mode,
                IBinder callerToken) throws FileNotFoundException, SecurityException {
            if (mode != null && mode.indexOf('w') != -1) {
@@ -1092,6 +1110,34 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
        return url;
    }

    /**
     * Implement this to support refresh of content identified by {@code uri}. By default, this
     * method returns false; providers who wish to implement this should return true to signal the
     * client that the provider has tried refreshing with its own implementation.
     * <p>
     * This allows clients to request an explicit refresh of content identified by {@code uri}.
     * <p>
     * Client code should only invoke this method when there is a strong indication (such as a user
     * initiated pull to refresh gesture) that the content is stale.
     * <p>
     * Remember to send {@link ContentResolver#notifyChange(Uri, android.database.ContentObserver)}
     * notifications when content changes.
     *
     * @param uri The Uri identifying the data to refresh.
     * @param args Additional options from the client. The definitions of these are specific to the
     *            content provider being called.
     * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if
     *            none. For example, if you called refresh on a particular uri, you should call
     *            {@link CancellationSignal#throwIfCanceled()} to check whether the client has
     *            canceled the refresh request.
     * @return true if the provider actually tried refreshing.
     * @hide
     */
    public boolean refresh(Uri uri, @Nullable Bundle args,
            @Nullable CancellationSignal cancellationSignal) {
        return false;
    }

    /**
     * @hide
     * Implementation when a caller has performed an insert on the content
+24 −0
Original line number Diff line number Diff line
@@ -234,6 +234,30 @@ public class ContentProviderClient implements AutoCloseable {
        }
    }

    /** @hide */
    public boolean refresh(Uri url, @Nullable Bundle args,
            @Nullable CancellationSignal cancellationSignal) throws RemoteException {
        Preconditions.checkNotNull(url, "url");

        beforeRemote();
        try {
            ICancellationSignal remoteCancellationSignal = null;
            if (cancellationSignal != null) {
                cancellationSignal.throwIfCanceled();
                remoteCancellationSignal = mContentProvider.createCancellationSignal();
                cancellationSignal.setRemote(remoteCancellationSignal);
            }
            return mContentProvider.refresh(mPackageName, url, args, remoteCancellationSignal);
        } catch (DeadObjectException e) {
            if (!mStable) {
                mContentResolver.unstableProviderDied(mContentProvider);
            }
            throw e;
        } finally {
            afterRemote();
        }
    }

    /** See {@link ContentProvider#insert ContentProvider.insert} */
    public @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues initialValues)
            throws RemoteException {
+37 −0
Original line number Diff line number Diff line
@@ -355,6 +355,20 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                    Uri.writeToParcel(reply, out);
                    return true;
                }

                case REFRESH_TRANSACTION: {
                    data.enforceInterface(IContentProvider.descriptor);
                    String callingPkg = data.readString();
                    Uri url = Uri.CREATOR.createFromParcel(data);
                    Bundle args = data.readBundle();
                    ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
                            data.readStrongBinder());

                    boolean out = refresh(callingPkg, url, args, signal);
                    reply.writeNoException();
                    reply.writeInt(out ? 0 : -1);
                    return true;
                }
            }
        } catch (Exception e) {
            DatabaseUtils.writeExceptionToParcel(reply, e);
@@ -761,5 +775,28 @@ final class ContentProviderProxy implements IContentProvider
        }
    }

    public boolean refresh(String callingPkg, Uri url, Bundle args, ICancellationSignal signal)
            throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        try {
            data.writeInterfaceToken(IContentProvider.descriptor);

            data.writeString(callingPkg);
            url.writeToParcel(data, 0);
            data.writeBundle(args);
            data.writeStrongBinder(signal != null ? signal.asBinder() : null);

            mRemote.transact(IContentProvider.REFRESH_TRANSACTION, data, reply, 0);

            DatabaseUtils.readExceptionFromParcel(reply);
            int success = reply.readInt();
            return (success == 0);
        } finally {
            data.recycle();
            reply.recycle();
        }
    }

    private IBinder mRemote;
}
+57 −0
Original line number Diff line number Diff line
@@ -193,6 +193,15 @@ public abstract class ContentResolver {
     */
    public static final String EXTRA_SIZE = "android.content.extra.SIZE";

    /**
     * An extra boolean describing whether a particular provider supports refresh
     * or not. If a provider supports refresh, it should include this key in its
     * returned Cursor as part of its query call.
     *
     * @hide
     */
    public static final String EXTRA_REFRESH_SUPPORTED = "android.content.extra.REFRESH_SUPPORTED";

    /**
     * This is the Android platform's base MIME type for a content: URI
     * containing a Cursor of a single item.  Applications should use this
@@ -663,6 +672,54 @@ public abstract class ContentResolver {
        }
    }

    /**
     * Implement this to support refresh of content identified by {@code uri}. By default, this
     * method returns false; providers who wish to implement this should return true to signal the
     * client that the provider has tried refreshing with its own implementation.
     * <p>
     * This allows clients to request an explicit refresh of content identified by {@code uri}.
     * <p>
     * Client code should only invoke this method when there is a strong indication (such as a user
     * initiated pull to refresh gesture) that the content is stale.
     * <p>
     * Remember to send {@link ContentResolver#notifyChange(Uri, android.database.ContentObserver)}
     * notifications when content changes.
     *
     * @param uri The Uri identifying the data to refresh.
     * @param args Additional options from the client. The definitions of these are specific to the
     *            content provider being called.
     * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if
     *            none. For example, if you called refresh on a particular uri, you should call
     *            {@link CancellationSignal#throwIfCanceled()} to check whether the client has
     *            canceled the refresh request.
     * @return true if the provider actually tried refreshing.
     * @hide
     */
    public final boolean refresh(@NonNull Uri url, @Nullable Bundle args,
            @Nullable CancellationSignal cancellationSignal) {
        Preconditions.checkNotNull(url, "url");
        IContentProvider provider = acquireProvider(url);
        if (provider == null) {
            return false;
        }

        try {
            ICancellationSignal remoteCancellationSignal = null;
            if (cancellationSignal != null) {
                cancellationSignal.throwIfCanceled();
                remoteCancellationSignal = provider.createCancellationSignal();
                cancellationSignal.setRemote(remoteCancellationSignal);
            }
            return provider.refresh(mPackageName, url, args, remoteCancellationSignal);
        } catch (RemoteException e) {
            // Arbitrary and not worth documenting, as Activity
            // Manager will kill this process shortly anyway.
            return false;
        } finally {
            releaseProvider(provider);
        }
    }

    /**
     * Open a stream on to the content associated with a content URI.  If there
     * is no data associated with the URI, FileNotFoundException is thrown.
+4 −0
Original line number Diff line number Diff line
@@ -65,6 +65,9 @@ public interface IContentProvider extends IInterface {
    public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException;
    public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException;

    public boolean refresh(String callingPkg, Uri url, @Nullable Bundle args,
            ICancellationSignal cancellationSignal) throws RemoteException;

    // Data interchange.
    public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
    public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
@@ -88,4 +91,5 @@ public interface IContentProvider extends IInterface {
    static final int CREATE_CANCELATION_SIGNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 23;
    static final int CANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 24;
    static final int UNCANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 25;
    static final int REFRESH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 26;
}
Loading