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
17package android.database;
18
19import android.net.Uri;
20import android.os.Handler;
21import 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 */
27public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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     */
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     */
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
208        public NotificationRunnable(boolean selfChange, Uri uri, int userId) {
209            mSelfChange = selfChange;
210            mUri = uri;
211            mUserId = userId;
212        }
213
214        @Override
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
223        public Transport(ContentObserver contentObserver) {
224            mContentObserver = contentObserver;
225        }
226
227        @Override
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
235        public void releaseContentObserver() {
236            mContentObserver = null;
237        }
238    }
239}
240