1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.database;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.annotation.UserIdInt;
23 import android.app.compat.CompatChanges;
24 import android.compat.annotation.ChangeId;
25 import android.compat.annotation.EnabledAfter;
26 import android.compat.annotation.UnsupportedAppUsage;
27 import android.content.ContentResolver.NotifyFlags;
28 import android.net.Uri;
29 import android.os.Handler;
30 import android.os.UserHandle;
31 
32 import java.util.Arrays;
33 import java.util.Collection;
34 import java.util.concurrent.Executor;
35 
36 /**
37  * Receives call backs for changes to content.
38  * Must be implemented by objects which are added to a {@link ContentObservable}.
39  */
40 @android.ravenwood.annotation.RavenwoodKeepWholeClass
41 public abstract class ContentObserver {
42     /**
43      * Starting in {@link android.os.Build.VERSION_CODES#R}, there is a new
44      * public API overload {@link #onChange(boolean, Uri, int)} that delivers a
45      * {@code int flags} argument.
46      * <p>
47      * Some apps may be relying on a previous hidden API that delivered a
48      * {@code int userId} argument, and this change is used to control delivery
49      * of the new {@code int flags} argument in its place.
50      */
51     @ChangeId
52     @EnabledAfter(targetSdkVersion=android.os.Build.VERSION_CODES.Q)
53     private static final long ADD_CONTENT_OBSERVER_FLAGS = 150939131L;
54     private final Object mLock = new Object();
55     private Transport mTransport; // guarded by mLock
56 
57     Handler mHandler;
58     private final Executor mExecutor;
59 
60     /**
61      * Creates a content observer.
62      *
63      * @param handler The handler to run {@link #onChange} on, or null if none.
64      */
ContentObserver(Handler handler)65     public ContentObserver(Handler handler) {
66         mHandler = handler;
67         mExecutor = null;
68     }
69 
70     /**
71      * @hide
72      * Creates a content observer with an executor.
73      *
74      * @param executor The executor to run {@link #onChange} on, or null if none.
75      * @param unused a second argument to avoid source incompatibility.
76      */
ContentObserver(@ullable Executor executor, int unused)77     public ContentObserver(@Nullable Executor executor, int unused) {
78         mExecutor = executor;
79     }
80 
81     /**
82      * Gets access to the binder transport object. Not for public consumption.
83      *
84      * {@hide}
85      */
getContentObserver()86     public IContentObserver getContentObserver() {
87         synchronized (mLock) {
88             if (mTransport == null) {
89                 mTransport = new Transport(this);
90             }
91             return mTransport;
92         }
93     }
94 
95     /**
96      * Gets access to the binder transport object, and unlinks the transport object
97      * from the ContentObserver. Not for public consumption.
98      *
99      * {@hide}
100      */
101     @UnsupportedAppUsage
releaseContentObserver()102     public IContentObserver releaseContentObserver() {
103         synchronized (mLock) {
104             final Transport oldTransport = mTransport;
105             if (oldTransport != null) {
106                 oldTransport.releaseContentObserver();
107                 mTransport = null;
108             }
109             return oldTransport;
110         }
111     }
112 
113     /**
114      * Returns true if this observer is interested receiving self-change notifications.
115      *
116      * Subclasses should override this method to indicate whether the observer
117      * is interested in receiving notifications for changes that it made to the
118      * content itself.
119      *
120      * @return True if self-change notifications should be delivered to the observer.
121      */
deliverSelfNotifications()122     public boolean deliverSelfNotifications() {
123         return false;
124     }
125 
126     /**
127      * This method is called when a content change occurs.
128      * <p>
129      * Subclasses should override this method to handle content changes.
130      * </p>
131      *
132      * @param selfChange True if this is a self-change notification.
133      */
onChange(boolean selfChange)134     public void onChange(boolean selfChange) {
135         // Do nothing.  Subclass should override.
136     }
137 
138     /**
139      * This method is called when a content change occurs.
140      * Includes the changed content Uri when available.
141      * <p>
142      * Subclasses should override this method to handle content changes. To
143      * ensure correct operation on older versions of the framework that did not
144      * provide richer arguments, applications should implement all overloads.
145      * <p>
146      * Example implementation:
147      * <pre><code>
148      * // Implement the onChange(boolean) method to delegate the change notification to
149      * // the onChange(boolean, Uri) method to ensure correct operation on older versions
150      * // of the framework that did not have the onChange(boolean, Uri) method.
151      * {@literal @Override}
152      * public void onChange(boolean selfChange) {
153      *     onChange(selfChange, null);
154      * }
155      *
156      * // Implement the onChange(boolean, Uri) method to take advantage of the new Uri argument.
157      * {@literal @Override}
158      * public void onChange(boolean selfChange, Uri uri) {
159      *     // Handle change.
160      * }
161      * </code></pre>
162      * </p>
163      *
164      * @param selfChange True if this is a self-change notification.
165      * @param uri The Uri of the changed content.
166      */
onChange(boolean selfChange, @Nullable Uri uri)167     public void onChange(boolean selfChange, @Nullable Uri uri) {
168         onChange(selfChange);
169     }
170 
171     /**
172      * This method is called when a content change occurs. Includes the changed
173      * content Uri when available.
174      * <p>
175      * Subclasses should override this method to handle content changes. To
176      * ensure correct operation on older versions of the framework that did not
177      * provide richer arguments, applications should implement all overloads.
178      *
179      * @param selfChange True if this is a self-change notification.
180      * @param uri The Uri of the changed content.
181      * @param flags Flags indicating details about this change.
182      */
onChange(boolean selfChange, @Nullable Uri uri, @NotifyFlags int flags)183     public void onChange(boolean selfChange, @Nullable Uri uri, @NotifyFlags int flags) {
184         onChange(selfChange, uri);
185     }
186 
187     /**
188      * This method is called when a content change occurs. Includes the changed
189      * content Uris when available.
190      * <p>
191      * Subclasses should override this method to handle content changes. To
192      * ensure correct operation on older versions of the framework that did not
193      * provide richer arguments, applications should implement all overloads.
194      *
195      * @param selfChange True if this is a self-change notification.
196      * @param uris The Uris of the changed content.
197      * @param flags Flags indicating details about this change.
198      */
onChange(boolean selfChange, @NonNull Collection<Uri> uris, @NotifyFlags int flags)199     public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
200             @NotifyFlags int flags) {
201         for (Uri uri : uris) {
202             onChange(selfChange, uri, flags);
203         }
204     }
205 
206     /**
207      * This method is called when a content change occurs. Includes the changed
208      * content Uris when available.
209      * <p>
210      * Subclasses should override this method to handle content changes. To
211      * ensure correct operation on older versions of the framework that did not
212      * provide richer arguments, applications should implement all overloads.
213      *
214      * @param selfChange True if this is a self-change notification.
215      * @param uris The Uris of the changed content.
216      * @param flags Flags indicating details about this change.
217      * @param user The corresponding {@link UserHandle} for the current notification.
218      *
219      * @hide
220      */
221     @SystemApi
onChange(boolean selfChange, @NonNull Collection<Uri> uris, @NotifyFlags int flags, @NonNull UserHandle user)222     public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
223             @NotifyFlags int flags, @NonNull UserHandle user) {
224         onChange(selfChange, uris, user.getIdentifier());
225     }
226 
227     /** @hide */
onChange(boolean selfChange, @NonNull Collection<Uri> uris, @NotifyFlags int flags, @UserIdInt int userId)228     public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
229             @NotifyFlags int flags, @UserIdInt int userId) {
230         // There are dozens of people relying on the hidden API inside the
231         // system UID, so hard-code the old behavior for all of them; for
232         // everyone else we gate based on a specific change
233         if (!isChangeEnabledAddContentObserverFlags()
234                 || android.os.Process.myUid() == android.os.Process.SYSTEM_UID) {
235             // Deliver userId through argument to preserve hidden API behavior
236             onChange(selfChange, uris, flags, UserHandle.of(userId));
237         } else {
238             onChange(selfChange, uris, flags);
239         }
240     }
241 
242     @android.ravenwood.annotation.RavenwoodReplace
isChangeEnabledAddContentObserverFlags()243     private static boolean isChangeEnabledAddContentObserverFlags() {
244         return CompatChanges.isChangeEnabled(ADD_CONTENT_OBSERVER_FLAGS);
245     }
246 
isChangeEnabledAddContentObserverFlags$ravenwood()247     private static boolean isChangeEnabledAddContentObserverFlags$ravenwood() {
248         return true;
249     }
250 
251     /**
252      * Dispatches a change notification to the observer.
253      * <p>
254      * If a {@link Handler} was supplied to the {@link ContentObserver}
255      * constructor, then a call to the {@link #onChange} method is posted to the
256      * handler's message queue. Otherwise, the {@link #onChange} method is
257      * invoked immediately on this thread.
258      *
259      * @deprecated Callers should migrate towards using a richer overload that
260      *             provides more details about the change, such as
261      *             {@link #dispatchChange(boolean, Collection, int)}.
262      */
263     @Deprecated
dispatchChange(boolean selfChange)264     public final void dispatchChange(boolean selfChange) {
265         dispatchChange(selfChange, null);
266     }
267 
268     /**
269      * Dispatches a change notification to the observer. Includes the changed
270      * content Uri when available.
271      * <p>
272      * If a {@link Handler} was supplied to the {@link ContentObserver}
273      * constructor, then a call to the {@link #onChange} method is posted to the
274      * handler's message queue. Otherwise, the {@link #onChange} method is
275      * invoked immediately on this thread.
276      *
277      * @param selfChange True if this is a self-change notification.
278      * @param uri The Uri of the changed content.
279      */
dispatchChange(boolean selfChange, @Nullable Uri uri)280     public final void dispatchChange(boolean selfChange, @Nullable Uri uri) {
281         dispatchChange(selfChange, uri, 0);
282     }
283 
284     /**
285      * Dispatches a change notification to the observer. Includes the changed
286      * content Uri when available.
287      * <p>
288      * If a {@link Handler} was supplied to the {@link ContentObserver}
289      * constructor, then a call to the {@link #onChange} method is posted to the
290      * handler's message queue. Otherwise, the {@link #onChange} method is
291      * invoked immediately on this thread.
292      *
293      * @param selfChange True if this is a self-change notification.
294      * @param uri The Uri of the changed content.
295      * @param flags Flags indicating details about this change.
296      */
dispatchChange(boolean selfChange, @Nullable Uri uri, @NotifyFlags int flags)297     public final void dispatchChange(boolean selfChange, @Nullable Uri uri,
298             @NotifyFlags int flags) {
299         dispatchChange(selfChange, Arrays.asList(uri), flags);
300     }
301 
302     /**
303      * Dispatches a change notification to the observer. Includes the changed
304      * content Uris when available.
305      * <p>
306      * If a {@link Handler} was supplied to the {@link ContentObserver}
307      * constructor, then a call to the {@link #onChange} method is posted to the
308      * handler's message queue. Otherwise, the {@link #onChange} method is
309      * invoked immediately on this thread.
310      *
311      * @param selfChange True if this is a self-change notification.
312      * @param uris The Uri of the changed content.
313      * @param flags Flags indicating details about this change.
314      */
dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris, @NotifyFlags int flags)315     public final void dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris,
316             @NotifyFlags int flags) {
317         dispatchChange(selfChange, uris, flags, UserHandle.getCallingUserId());
318     }
319 
320     /** @hide */
dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris, @NotifyFlags int flags, @UserIdInt int userId)321     public final void dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris,
322             @NotifyFlags int flags, @UserIdInt int userId) {
323         if (mExecutor != null) {
324             mExecutor.execute(() -> {
325                 onChange(selfChange, uris, flags, userId);
326             });
327         } else if (mHandler != null) {
328             // Supporting Handler directly rather than wrapping in a HandlerExecutor
329             //  avoids introducing a RejectedExecutionException for legacy code when
330             //  the post fails.
331             mHandler.post(() -> {
332                 onChange(selfChange, uris, flags, userId);
333             });
334         } else {
335             onChange(selfChange, uris, flags, userId);
336         }
337     }
338 
339     private static final class Transport extends IContentObserver.Stub {
340         private ContentObserver mContentObserver;
341 
Transport(ContentObserver contentObserver)342         public Transport(ContentObserver contentObserver) {
343             mContentObserver = contentObserver;
344         }
345 
346         @Override
onChange(boolean selfChange, Uri uri, int userId)347         public void onChange(boolean selfChange, Uri uri, int userId) {
348             // This is kept intact purely for apps using hidden APIs, to
349             // redirect to the updated implementation
350             onChangeEtc(selfChange, new Uri[] { uri }, 0, userId);
351         }
352 
353         @Override
onChangeEtc(boolean selfChange, Uri[] uris, int flags, int userId)354         public void onChangeEtc(boolean selfChange, Uri[] uris, int flags, int userId) {
355             ContentObserver contentObserver = mContentObserver;
356             if (contentObserver != null) {
357                 contentObserver.dispatchChange(selfChange, Arrays.asList(uris), flags, userId);
358             }
359         }
360 
releaseContentObserver()361         public void releaseContentObserver() {
362             mContentObserver = null;
363         }
364     }
365 }
366