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.compat.annotation.UnsupportedAppUsage;
20 import android.net.Uri;
21 import android.os.Handler;
22 import android.os.UserHandle;
23 
24 /**
25  * Receives call backs for changes to content.
26  * Must be implemented by objects which are added to a {@link ContentObservable}.
27  */
28 public abstract class ContentObserver {
29     private final Object mLock = new Object();
30     private Transport mTransport; // guarded by mLock
31 
32     Handler mHandler;
33 
34     /**
35      * Creates a content observer.
36      *
37      * @param handler The handler to run {@link #onChange} on, or null if none.
38      */
ContentObserver(Handler handler)39     public ContentObserver(Handler handler) {
40         mHandler = handler;
41     }
42 
43     /**
44      * Gets access to the binder transport object. Not for public consumption.
45      *
46      * {@hide}
47      */
getContentObserver()48     public IContentObserver getContentObserver() {
49         synchronized (mLock) {
50             if (mTransport == null) {
51                 mTransport = new Transport(this);
52             }
53             return mTransport;
54         }
55     }
56 
57     /**
58      * Gets access to the binder transport object, and unlinks the transport object
59      * from the ContentObserver. Not for public consumption.
60      *
61      * {@hide}
62      */
63     @UnsupportedAppUsage
releaseContentObserver()64     public IContentObserver releaseContentObserver() {
65         synchronized (mLock) {
66             final Transport oldTransport = mTransport;
67             if (oldTransport != null) {
68                 oldTransport.releaseContentObserver();
69                 mTransport = null;
70             }
71             return oldTransport;
72         }
73     }
74 
75     /**
76      * Returns true if this observer is interested receiving self-change notifications.
77      *
78      * Subclasses should override this method to indicate whether the observer
79      * is interested in receiving notifications for changes that it made to the
80      * content itself.
81      *
82      * @return True if self-change notifications should be delivered to the observer.
83      */
deliverSelfNotifications()84     public boolean deliverSelfNotifications() {
85         return false;
86     }
87 
88     /**
89      * This method is called when a content change occurs.
90      * <p>
91      * Subclasses should override this method to handle content changes.
92      * </p>
93      *
94      * @param selfChange True if this is a self-change notification.
95      */
onChange(boolean selfChange)96     public void onChange(boolean selfChange) {
97         // Do nothing.  Subclass should override.
98     }
99 
100     /**
101      * This method is called when a content change occurs.
102      * Includes the changed content Uri when available.
103      * <p>
104      * Subclasses should override this method to handle content changes.
105      * To ensure correct operation on older versions of the framework that
106      * did not provide a Uri argument, applications should also implement
107      * the {@link #onChange(boolean)} overload of this method whenever they
108      * implement the {@link #onChange(boolean, Uri)} overload.
109      * </p><p>
110      * Example implementation:
111      * <pre><code>
112      * // Implement the onChange(boolean) method to delegate the change notification to
113      * // the onChange(boolean, Uri) method to ensure correct operation on older versions
114      * // of the framework that did not have the onChange(boolean, Uri) method.
115      * {@literal @Override}
116      * public void onChange(boolean selfChange) {
117      *     onChange(selfChange, null);
118      * }
119      *
120      * // Implement the onChange(boolean, Uri) method to take advantage of the new Uri argument.
121      * {@literal @Override}
122      * public void onChange(boolean selfChange, Uri uri) {
123      *     // Handle change.
124      * }
125      * </code></pre>
126      * </p>
127      *
128      * @param selfChange True if this is a self-change notification.
129      * @param uri The Uri of the changed content, or null if unknown.
130      */
onChange(boolean selfChange, Uri uri)131     public void onChange(boolean selfChange, Uri uri) {
132         onChange(selfChange);
133     }
134 
135     /**
136      * Dispatches a change notification to the observer. Includes the changed
137      * content Uri when available and also the user whose content changed.
138      *
139      * @param selfChange True if this is a self-change notification.
140      * @param uri The Uri of the changed content, or null if unknown.
141      * @param userId The user whose content changed. Can be either a specific
142      *         user or {@link UserHandle#USER_ALL}.
143      *
144      * @hide
145      */
onChange(boolean selfChange, Uri uri, int userId)146     public void onChange(boolean selfChange, Uri uri, int userId) {
147         onChange(selfChange, uri);
148     }
149 
150     /**
151      * Dispatches a change notification to the observer.
152      * <p>
153      * If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
154      * then a call to the {@link #onChange} method is posted to the handler's message queue.
155      * Otherwise, the {@link #onChange} method is invoked immediately on this thread.
156      * </p>
157      *
158      * @param selfChange True if this is a self-change notification.
159      *
160      * @deprecated Use {@link #dispatchChange(boolean, Uri)} instead.
161      */
162     @Deprecated
dispatchChange(boolean selfChange)163     public final void dispatchChange(boolean selfChange) {
164         dispatchChange(selfChange, null);
165     }
166 
167     /**
168      * Dispatches a change notification to the observer.
169      * Includes the changed content Uri when available.
170      * <p>
171      * If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
172      * then a call to the {@link #onChange} method is posted to the handler's message queue.
173      * Otherwise, the {@link #onChange} method is invoked immediately on this thread.
174      * </p>
175      *
176      * @param selfChange True if this is a self-change notification.
177      * @param uri The Uri of the changed content, or null if unknown.
178      */
dispatchChange(boolean selfChange, Uri uri)179     public final void dispatchChange(boolean selfChange, Uri uri) {
180         dispatchChange(selfChange, uri, UserHandle.getCallingUserId());
181     }
182 
183     /**
184      * Dispatches a change notification to the observer. Includes the changed
185      * content Uri when available and also the user whose content changed.
186      * <p>
187      * If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
188      * then a call to the {@link #onChange} method is posted to the handler's message queue.
189      * Otherwise, the {@link #onChange} method is invoked immediately on this thread.
190      * </p>
191      *
192      * @param selfChange True if this is a self-change notification.
193      * @param uri The Uri of the changed content, or null if unknown.
194      * @param userId The user whose content changed.
195      */
dispatchChange(boolean selfChange, Uri uri, int userId)196     private void dispatchChange(boolean selfChange, Uri uri, int userId) {
197         if (mHandler == null) {
198             onChange(selfChange, uri, userId);
199         } else {
200             mHandler.post(new NotificationRunnable(selfChange, uri, userId));
201         }
202     }
203 
204 
205     private final class NotificationRunnable implements Runnable {
206         private final boolean mSelfChange;
207         private final Uri mUri;
208         private final int mUserId;
209 
NotificationRunnable(boolean selfChange, Uri uri, int userId)210         public NotificationRunnable(boolean selfChange, Uri uri, int userId) {
211             mSelfChange = selfChange;
212             mUri = uri;
213             mUserId = userId;
214         }
215 
216         @Override
run()217         public void run() {
218             ContentObserver.this.onChange(mSelfChange, mUri, mUserId);
219         }
220     }
221 
222     private static final class Transport extends IContentObserver.Stub {
223         private ContentObserver mContentObserver;
224 
Transport(ContentObserver contentObserver)225         public Transport(ContentObserver contentObserver) {
226             mContentObserver = contentObserver;
227         }
228 
229         @Override
onChange(boolean selfChange, Uri uri, int userId)230         public void onChange(boolean selfChange, Uri uri, int userId) {
231             ContentObserver contentObserver = mContentObserver;
232             if (contentObserver != null) {
233                 contentObserver.dispatchChange(selfChange, uri, userId);
234             }
235         }
236 
releaseContentObserver()237         public void releaseContentObserver() {
238             mContentObserver = null;
239         }
240     }
241 }
242