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