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 
35 /**
36  * Receives call backs for changes to content.
37  * Must be implemented by objects which are added to a {@link ContentObservable}.
38  */
39 public abstract class ContentObserver {
40     /**
41      * Starting in {@link android.os.Build.VERSION_CODES#R}, there is a new
42      * public API overload {@link #onChange(boolean, Uri, int)} that delivers a
43      * {@code int flags} argument.
44      * <p>
45      * Some apps may be relying on a previous hidden API that delivered a
46      * {@code int userId} argument, and this change is used to control delivery
47      * of the new {@code int flags} argument in its place.
48      */
49     @ChangeId
50     @EnabledAfter(targetSdkVersion=android.os.Build.VERSION_CODES.Q)
51     private static final long ADD_CONTENT_OBSERVER_FLAGS = 150939131L;
52 
53     private final Object mLock = new Object();
54     private Transport mTransport; // guarded by mLock
55 
56     Handler mHandler;
57 
58     /**
59      * Creates a content observer.
60      *
61      * @param handler The handler to run {@link #onChange} on, or null if none.
62      */
ContentObserver(Handler handler)63     public ContentObserver(Handler handler) {
64         mHandler = handler;
65     }
66 
67     /**
68      * Gets access to the binder transport object. Not for public consumption.
69      *
70      * {@hide}
71      */
getContentObserver()72     public IContentObserver getContentObserver() {
73         synchronized (mLock) {
74             if (mTransport == null) {
75                 mTransport = new Transport(this);
76             }
77             return mTransport;
78         }
79     }
80 
81     /**
82      * Gets access to the binder transport object, and unlinks the transport object
83      * from the ContentObserver. Not for public consumption.
84      *
85      * {@hide}
86      */
87     @UnsupportedAppUsage
releaseContentObserver()88     public IContentObserver releaseContentObserver() {
89         synchronized (mLock) {
90             final Transport oldTransport = mTransport;
91             if (oldTransport != null) {
92                 oldTransport.releaseContentObserver();
93                 mTransport = null;
94             }
95             return oldTransport;
96         }
97     }
98 
99     /**
100      * Returns true if this observer is interested receiving self-change notifications.
101      *
102      * Subclasses should override this method to indicate whether the observer
103      * is interested in receiving notifications for changes that it made to the
104      * content itself.
105      *
106      * @return True if self-change notifications should be delivered to the observer.
107      */
deliverSelfNotifications()108     public boolean deliverSelfNotifications() {
109         return false;
110     }
111 
112     /**
113      * This method is called when a content change occurs.
114      * <p>
115      * Subclasses should override this method to handle content changes.
116      * </p>
117      *
118      * @param selfChange True if this is a self-change notification.
119      */
onChange(boolean selfChange)120     public void onChange(boolean selfChange) {
121         // Do nothing.  Subclass should override.
122     }
123 
124     /**
125      * This method is called when a content change occurs.
126      * Includes the changed content Uri when available.
127      * <p>
128      * Subclasses should override this method to handle content changes. To
129      * ensure correct operation on older versions of the framework that did not
130      * provide richer arguments, applications should implement all overloads.
131      * <p>
132      * Example implementation:
133      * <pre><code>
134      * // Implement the onChange(boolean) method to delegate the change notification to
135      * // the onChange(boolean, Uri) method to ensure correct operation on older versions
136      * // of the framework that did not have the onChange(boolean, Uri) method.
137      * {@literal @Override}
138      * public void onChange(boolean selfChange) {
139      *     onChange(selfChange, null);
140      * }
141      *
142      * // Implement the onChange(boolean, Uri) method to take advantage of the new Uri argument.
143      * {@literal @Override}
144      * public void onChange(boolean selfChange, Uri uri) {
145      *     // Handle change.
146      * }
147      * </code></pre>
148      * </p>
149      *
150      * @param selfChange True if this is a self-change notification.
151      * @param uri The Uri of the changed content.
152      */
onChange(boolean selfChange, @Nullable Uri uri)153     public void onChange(boolean selfChange, @Nullable Uri uri) {
154         onChange(selfChange);
155     }
156 
157     /**
158      * This method is called when a content change occurs. Includes the changed
159      * content Uri when available.
160      * <p>
161      * Subclasses should override this method to handle content changes. To
162      * ensure correct operation on older versions of the framework that did not
163      * provide richer arguments, applications should implement all overloads.
164      *
165      * @param selfChange True if this is a self-change notification.
166      * @param uri The Uri of the changed content.
167      * @param flags Flags indicating details about this change.
168      */
onChange(boolean selfChange, @Nullable Uri uri, @NotifyFlags int flags)169     public void onChange(boolean selfChange, @Nullable Uri uri, @NotifyFlags int flags) {
170         onChange(selfChange, uri);
171     }
172 
173     /**
174      * This method is called when a content change occurs. Includes the changed
175      * content Uris when available.
176      * <p>
177      * Subclasses should override this method to handle content changes. To
178      * ensure correct operation on older versions of the framework that did not
179      * provide richer arguments, applications should implement all overloads.
180      *
181      * @param selfChange True if this is a self-change notification.
182      * @param uris The Uris of the changed content.
183      * @param flags Flags indicating details about this change.
184      */
onChange(boolean selfChange, @NonNull Collection<Uri> uris, @NotifyFlags int flags)185     public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
186             @NotifyFlags int flags) {
187         for (Uri uri : uris) {
188             onChange(selfChange, uri, flags);
189         }
190     }
191 
192     /**
193      * This method is called when a content change occurs. Includes the changed
194      * content Uris when available.
195      * <p>
196      * Subclasses should override this method to handle content changes. To
197      * ensure correct operation on older versions of the framework that did not
198      * provide richer arguments, applications should implement all overloads.
199      *
200      * @param selfChange True if this is a self-change notification.
201      * @param uris The Uris of the changed content.
202      * @param flags Flags indicating details about this change.
203      * @param user The corresponding {@link UserHandle} for the current notification.
204      *
205      * @hide
206      */
207     @SystemApi
onChange(boolean selfChange, @NonNull Collection<Uri> uris, @NotifyFlags int flags, @NonNull UserHandle user)208     public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
209             @NotifyFlags int flags, @NonNull UserHandle user) {
210         onChange(selfChange, uris, user.getIdentifier());
211     }
212 
213     /** @hide */
onChange(boolean selfChange, @NonNull Collection<Uri> uris, @NotifyFlags int flags, @UserIdInt int userId)214     public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
215             @NotifyFlags int flags, @UserIdInt int userId) {
216         // There are dozens of people relying on the hidden API inside the
217         // system UID, so hard-code the old behavior for all of them; for
218         // everyone else we gate based on a specific change
219         if (!CompatChanges.isChangeEnabled(ADD_CONTENT_OBSERVER_FLAGS)
220                 || android.os.Process.myUid() == android.os.Process.SYSTEM_UID) {
221             // Deliver userId through argument to preserve hidden API behavior
222             onChange(selfChange, uris, flags, UserHandle.of(userId));
223         } else {
224             onChange(selfChange, uris, flags);
225         }
226     }
227 
228     /**
229      * Dispatches a change notification to the observer.
230      * <p>
231      * If a {@link Handler} was supplied to the {@link ContentObserver}
232      * constructor, then a call to the {@link #onChange} method is posted to the
233      * handler's message queue. Otherwise, the {@link #onChange} method is
234      * invoked immediately on this thread.
235      *
236      * @deprecated Callers should migrate towards using a richer overload that
237      *             provides more details about the change, such as
238      *             {@link #dispatchChange(boolean, Collection, int)}.
239      */
240     @Deprecated
dispatchChange(boolean selfChange)241     public final void dispatchChange(boolean selfChange) {
242         dispatchChange(selfChange, null);
243     }
244 
245     /**
246      * Dispatches a change notification to the observer. Includes the changed
247      * content Uri when available.
248      * <p>
249      * If a {@link Handler} was supplied to the {@link ContentObserver}
250      * constructor, then a call to the {@link #onChange} method is posted to the
251      * handler's message queue. Otherwise, the {@link #onChange} method is
252      * invoked immediately on this thread.
253      *
254      * @param selfChange True if this is a self-change notification.
255      * @param uri The Uri of the changed content.
256      */
dispatchChange(boolean selfChange, @Nullable Uri uri)257     public final void dispatchChange(boolean selfChange, @Nullable Uri uri) {
258         dispatchChange(selfChange, uri, 0);
259     }
260 
261     /**
262      * Dispatches a change notification to the observer. Includes the changed
263      * content Uri when available.
264      * <p>
265      * If a {@link Handler} was supplied to the {@link ContentObserver}
266      * constructor, then a call to the {@link #onChange} method is posted to the
267      * handler's message queue. Otherwise, the {@link #onChange} method is
268      * invoked immediately on this thread.
269      *
270      * @param selfChange True if this is a self-change notification.
271      * @param uri The Uri of the changed content.
272      * @param flags Flags indicating details about this change.
273      */
dispatchChange(boolean selfChange, @Nullable Uri uri, @NotifyFlags int flags)274     public final void dispatchChange(boolean selfChange, @Nullable Uri uri,
275             @NotifyFlags int flags) {
276         dispatchChange(selfChange, Arrays.asList(uri), flags);
277     }
278 
279     /**
280      * Dispatches a change notification to the observer. Includes the changed
281      * content Uris when available.
282      * <p>
283      * If a {@link Handler} was supplied to the {@link ContentObserver}
284      * constructor, then a call to the {@link #onChange} method is posted to the
285      * handler's message queue. Otherwise, the {@link #onChange} method is
286      * invoked immediately on this thread.
287      *
288      * @param selfChange True if this is a self-change notification.
289      * @param uris The Uri of the changed content.
290      * @param flags Flags indicating details about this change.
291      */
dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris, @NotifyFlags int flags)292     public final void dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris,
293             @NotifyFlags int flags) {
294         dispatchChange(selfChange, uris, flags, UserHandle.getCallingUserId());
295     }
296 
297     /** @hide */
dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris, @NotifyFlags int flags, @UserIdInt int userId)298     public final void dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris,
299             @NotifyFlags int flags, @UserIdInt int userId) {
300         if (mHandler == null) {
301             onChange(selfChange, uris, flags, userId);
302         } else {
303             mHandler.post(() -> {
304                 onChange(selfChange, uris, flags, userId);
305             });
306         }
307     }
308 
309     private static final class Transport extends IContentObserver.Stub {
310         private ContentObserver mContentObserver;
311 
Transport(ContentObserver contentObserver)312         public Transport(ContentObserver contentObserver) {
313             mContentObserver = contentObserver;
314         }
315 
316         @Override
onChange(boolean selfChange, Uri uri, int userId)317         public void onChange(boolean selfChange, Uri uri, int userId) {
318             // This is kept intact purely for apps using hidden APIs, to
319             // redirect to the updated implementation
320             onChangeEtc(selfChange, new Uri[] { uri }, 0, userId);
321         }
322 
323         @Override
onChangeEtc(boolean selfChange, Uri[] uris, int flags, int userId)324         public void onChangeEtc(boolean selfChange, Uri[] uris, int flags, int userId) {
325             ContentObserver contentObserver = mContentObserver;
326             if (contentObserver != null) {
327                 contentObserver.dispatchChange(selfChange, Arrays.asList(uris), flags, userId);
328             }
329         }
330 
releaseContentObserver()331         public void releaseContentObserver() {
332             mContentObserver = null;
333         }
334     }
335 }
336