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