Merge "Allow sending of bulk Uri change notifications."

This commit is contained in:
Jeff Sharkey
2019-11-14 03:48:02 +00:00
committed by Android (Google) Code Review
5 changed files with 125 additions and 32 deletions

View File

@@ -9650,8 +9650,9 @@ package android.content {
method public static boolean isSyncPending(android.accounts.Account, String);
method @NonNull public android.graphics.Bitmap loadThumbnail(@NonNull android.net.Uri, @NonNull android.util.Size, @Nullable android.os.CancellationSignal) throws java.io.IOException;
method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver);
method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, boolean);
method @Deprecated public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, boolean);
method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, int);
method public void notifyChange(@NonNull Iterable<android.net.Uri>, @Nullable android.database.ContentObserver, int);
method @Nullable public final android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
method @Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException;
method @Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;

View File

@@ -65,6 +65,7 @@ import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
import android.util.Size;
import android.util.SparseArray;
import com.android.internal.util.MimeIconUtils;
import com.android.internal.util.Preconditions;
@@ -2381,15 +2382,15 @@ public abstract class ContentResolver implements ContentInterface {
* true.
* @param syncToNetwork If true, same as {@link #NOTIFY_SYNC_TO_NETWORK}.
* @see #requestSync(android.accounts.Account, String, android.os.Bundle)
* @deprecated callers should consider migrating to
* {@link #notifyChange(Uri, ContentObserver, int)}, as it
* offers support for many more options than just
* {@link #NOTIFY_SYNC_TO_NETWORK}.
*/
@Deprecated
public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
boolean syncToNetwork) {
Preconditions.checkNotNull(uri, "uri");
notifyChange(
ContentProvider.getUriWithoutUserId(uri),
observer,
syncToNetwork,
ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
notifyChange(uri, observer, syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0);
}
/**
@@ -2398,10 +2399,10 @@ public abstract class ContentResolver implements ContentInterface {
* To observe events sent through this call, use
* {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
* <p>
* If syncToNetwork is true, this will attempt to schedule a local sync
* using the sync adapter that's registered for the authority of the
* provided uri. No account will be passed to the sync adapter, so all
* matching accounts will be synchronized.
* If {@link #NOTIFY_SYNC_TO_NETWORK} is set, this will attempt to schedule
* a local sync using the sync adapter that's registered for the authority
* of the provided uri. No account will be passed to the sync adapter, so
* all matching accounts will be synchronized.
* <p>
* Starting in {@link android.os.Build.VERSION_CODES#O}, all content
* notifications must be backed by a valid {@link ContentProvider}.
@@ -2426,22 +2427,72 @@ public abstract class ContentResolver implements ContentInterface {
ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
}
/**
* Notify registered observers that several rows have been updated.
* <p>
* To observe events sent through this call, use
* {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
* <p>
* If {@link #NOTIFY_SYNC_TO_NETWORK} is set, this will attempt to schedule
* a local sync using the sync adapter that's registered for the authority
* of the provided uri. No account will be passed to the sync adapter, so
* all matching accounts will be synchronized.
* <p>
* Starting in {@link android.os.Build.VERSION_CODES#O}, all content
* notifications must be backed by a valid {@link ContentProvider}.
*
* @param uris The uris of the content that was changed.
* @param observer The observer that originated the change, may be
* <code>null</null>. The observer that originated the change
* will only receive the notification if it has requested to
* receive self-change notifications by implementing
* {@link ContentObserver#deliverSelfNotifications()} to return
* true.
* @param flags Flags such as {@link #NOTIFY_SYNC_TO_NETWORK} or
* {@link #NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS}.
*/
public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer,
@NotifyFlags int flags) {
Preconditions.checkNotNull(uris, "uris");
// Cluster based on user ID
final SparseArray<ArrayList<Uri>> clusteredByUser = new SparseArray<>();
for (Uri uri : uris) {
final int userId = ContentProvider.getUserIdFromUri(uri, mContext.getUserId());
ArrayList<Uri> list = clusteredByUser.get(userId);
if (list == null) {
list = new ArrayList<>();
clusteredByUser.put(userId, list);
}
list.add(ContentProvider.getUriWithoutUserId(uri));
}
for (int i = 0; i < clusteredByUser.size(); i++) {
final int userId = clusteredByUser.keyAt(i);
final ArrayList<Uri> list = clusteredByUser.valueAt(i);
notifyChange(list.toArray(new Uri[list.size()]), observer, flags, userId);
}
}
/**
* Notify registered observers within the designated user(s) that a row was updated.
*
* @deprecated callers should consider migrating to
* {@link #notifyChange(Uri, ContentObserver, int)}, as it
* offers support for many more options than just
* {@link #NOTIFY_SYNC_TO_NETWORK}.
* @hide
*/
@Deprecated
public void notifyChange(@NonNull Uri uri, ContentObserver observer, boolean syncToNetwork,
@UserIdInt int userHandle) {
try {
getContentService().notifyChange(
uri, observer == null ? null : observer.getContentObserver(),
observer != null && observer.deliverSelfNotifications(),
syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0,
userHandle, mTargetSdkVersion, mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
notifyChange(uri, observer, syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0, userHandle);
}
/** {@hide} */
public void notifyChange(@NonNull Uri uri, ContentObserver observer, @NotifyFlags int flags,
@UserIdInt int userHandle) {
notifyChange(new Uri[] { uri }, observer, flags, userHandle);
}
/**
@@ -2449,11 +2500,11 @@ public abstract class ContentResolver implements ContentInterface {
*
* @hide
*/
public void notifyChange(@NonNull Uri uri, ContentObserver observer, @NotifyFlags int flags,
public void notifyChange(@NonNull Uri[] uris, ContentObserver observer, @NotifyFlags int flags,
@UserIdInt int userHandle) {
try {
getContentService().notifyChange(
uri, observer == null ? null : observer.getContentObserver(),
uris, observer == null ? null : observer.getContentObserver(),
observer != null && observer.deliverSelfNotifications(), flags,
userHandle, mTargetSdkVersion, mContext.getPackageName());
} catch (RemoteException e) {

View File

@@ -51,7 +51,7 @@ interface IContentService {
* hold the INTERACT_ACROSS_USERS_FULL permission. Pseudousers USER_ALL
* USER_CURRENT are properly interpreted.
*/
void notifyChange(in Uri uri, IContentObserver observer,
void notifyChange(in Uri[] uris, IContentObserver observer,
boolean observerWantsSelfNotifications, int flags,
int userHandle, int targetSdkVersion, String callingPackage);

View File

@@ -394,6 +394,15 @@ public final class ContentService extends IContentService.Stub {
* allowed.
*/
@Override
public void notifyChange(Uri[] uris, IContentObserver observer,
boolean observerWantsSelfNotifications, int flags, int userHandle,
int targetSdkVersion, String callingPackage) {
for (Uri uri : uris) {
notifyChange(uri, observer, observerWantsSelfNotifications, flags, userHandle,
targetSdkVersion, callingPackage);
}
}
public void notifyChange(Uri uri, IContentObserver observer,
boolean observerWantsSelfNotifications, int flags, int userHandle,
int targetSdkVersion, String callingPackage) {

View File

@@ -16,6 +16,8 @@
package android.test.mock;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
@@ -130,17 +132,47 @@ public class MockContentResolver extends ContentResolver {
}
/**
* Overrides {@link android.content.ContentResolver#notifyChange(Uri, ContentObserver, boolean)
* ContentResolver.notifChange(Uri, ContentObserver, boolean)}. All parameters are ignored.
* The method hides providers linked to MockContentResolver from other observers in the system.
*
* @param uri (Ignored) The uri of the content provider.
* @param observer (Ignored) The observer that originated the change.
* @param syncToNetwork (Ignored) If true, attempt to sync the change to the network.
* Overrides the behavior from the parent class to completely ignore any
* content notifications sent to this object. This effectively hides clients
* from observers elsewhere in the system.
*/
@Override
public void notifyChange(Uri uri,
ContentObserver observer,
public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer) {
}
/**
* Overrides the behavior from the parent class to completely ignore any
* content notifications sent to this object. This effectively hides clients
* from observers elsewhere in the system.
*
* @deprecated callers should consider migrating to
* {@link #notifyChange(Uri, ContentObserver, int)}, as it
* offers support for many more options than just
* {@link #NOTIFY_SYNC_TO_NETWORK}.
*/
@Override
@Deprecated
public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
boolean syncToNetwork) {
}
/**
* Overrides the behavior from the parent class to completely ignore any
* content notifications sent to this object. This effectively hides clients
* from observers elsewhere in the system.
*/
@Override
public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
@NotifyFlags int flags) {
}
/**
* Overrides the behavior from the parent class to completely ignore any
* content notifications sent to this object. This effectively hides clients
* from observers elsewhere in the system.
*/
@Override
public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer,
@NotifyFlags int flags) {
}
}