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