From c06b02ddba46bd1b467fa7f9c42c35db3209795c Mon Sep 17 00:00:00 2001 From: Xiaoyu Jin Date: Thu, 28 Oct 2021 04:52:44 +0000 Subject: [PATCH] Add @SystemApi registerContentObserverForAllUsers in ContentResolver Also add ContentObserver#onChange(boolean, Collection, int, UserHandle) so clients can know the corresponding UserHandle for the notification. Bug: 203606981 Test: atest CtsContentTestCases and manual testing to verify the observer can get notifications for all the users. Change-Id: Icec7e70b71d7de1c15faf1736539f169856304a8 --- core/api/system-current.txt | 9 ++++++ .../java/android/content/ContentResolver.java | 32 +++++++++++++++++++ .../android/database/ContentObserver.java | 24 +++++++++++++- 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/core/api/system-current.txt b/core/api/system-current.txt index a255ce3f19d8a..2d762f0612211 100755 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2405,6 +2405,7 @@ package android.content { method @NonNull public static java.io.File encodeToFile(@NonNull android.net.Uri); method @Nullable @RequiresPermission("android.permission.CACHE_CONTENT") public android.os.Bundle getCache(@NonNull android.net.Uri); method @RequiresPermission("android.permission.CACHE_CONTENT") public void putCache(@NonNull android.net.Uri, @Nullable android.os.Bundle); + method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public final void registerContentObserverForAllUsers(@NonNull android.net.Uri, boolean, @NonNull android.database.ContentObserver); } public abstract class Context { @@ -3147,6 +3148,14 @@ package android.content.rollback { } +package android.database { + + public abstract class ContentObserver { + method public void onChange(boolean, @NonNull java.util.Collection, int, @NonNull android.os.UserHandle); + } + +} + package android.debug { public class AdbManager { diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 563b6cf0349cf..a9a232518e5f6 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -2664,6 +2664,38 @@ public abstract class ContentResolver implements ContentInterface { ContentProvider.getUserIdFromUri(uri, mContext.getUserId())); } + /** + * Same as {@link #registerContentObserver(Uri, boolean, ContentObserver)}, but the observer + * registered will get content change notifications from all users. + * {@link ContentObserver#onChange(boolean, Collection, int, UserHandle)} should be + * overwritten to get the corresponding {@link UserHandle} for that notification. + * + * @param uri The URI to watch for changes. This can be a specific row URI, + * or a base URI for a whole class of content. + * @param notifyForDescendants When false, the observer will be notified + * whenever a change occurs to the exact URI specified by + * uri or to one of the URI's ancestors in the path + * hierarchy. When true, the observer will also be notified + * whenever a change occurs to the URI's descendants in the path + * hierarchy. + * @param observer The object that receives callbacks when changes occur. + * @hide + * @see #unregisterContentObserver + */ + @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) + @SystemApi + public final void registerContentObserverForAllUsers(@NonNull Uri uri, + boolean notifyForDescendants, + @NonNull ContentObserver observer) { + Objects.requireNonNull(uri, "uri"); + Objects.requireNonNull(observer, "observer"); + registerContentObserver( + ContentProvider.getUriWithoutUserId(uri), + notifyForDescendants, + observer, + UserHandle.USER_ALL); + } + /** @hide - designated user version */ @UnsupportedAppUsage public final void registerContentObserver(Uri uri, boolean notifyForDescendents, diff --git a/core/java/android/database/ContentObserver.java b/core/java/android/database/ContentObserver.java index 578d53b17bf96..c27ee51b93154 100644 --- a/core/java/android/database/ContentObserver.java +++ b/core/java/android/database/ContentObserver.java @@ -18,6 +18,7 @@ package android.database; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.annotation.UserIdInt; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; @@ -188,6 +189,27 @@ public abstract class ContentObserver { } } + /** + * This method is called when a content change occurs. Includes the changed + * content Uris when available. + *

+ * Subclasses should override this method to handle content changes. To + * ensure correct operation on older versions of the framework that did not + * provide richer arguments, applications should implement all overloads. + * + * @param selfChange True if this is a self-change notification. + * @param uris The Uris of the changed content. + * @param flags Flags indicating details about this change. + * @param user The corresponding {@link UserHandle} for the current notification. + * + * @hide + */ + @SystemApi + public void onChange(boolean selfChange, @NonNull Collection uris, + @NotifyFlags int flags, @NonNull UserHandle user) { + onChange(selfChange, uris, user.getIdentifier()); + } + /** @hide */ public void onChange(boolean selfChange, @NonNull Collection uris, @NotifyFlags int flags, @UserIdInt int userId) { @@ -197,7 +219,7 @@ public abstract class ContentObserver { if (!CompatChanges.isChangeEnabled(ADD_CONTENT_OBSERVER_FLAGS) || android.os.Process.myUid() == android.os.Process.SYSTEM_UID) { // Deliver userId through argument to preserve hidden API behavior - onChange(selfChange, uris, userId); + onChange(selfChange, uris, flags, UserHandle.of(userId)); } else { onChange(selfChange, uris, flags); }