/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.database;
import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
/**
* Receives call backs for changes to content.
* Must be implemented by objects which are added to a {@link ContentObservable}.
*/
public abstract class ContentObserver {
private final Object mLock = new Object();
private Transport mTransport; // guarded by mLock
Handler mHandler;
/**
* Creates a content observer.
*
* @param handler The handler to run {@link #onChange} on, or null if none.
*/
public ContentObserver(Handler handler) {
mHandler = handler;
}
/**
* Gets access to the binder transport object. Not for public consumption.
*
* {@hide}
*/
public IContentObserver getContentObserver() {
synchronized (mLock) {
if (mTransport == null) {
mTransport = new Transport(this);
}
return mTransport;
}
}
/**
* Gets access to the binder transport object, and unlinks the transport object
* from the ContentObserver. Not for public consumption.
*
* {@hide}
*/
public IContentObserver releaseContentObserver() {
synchronized (mLock) {
final Transport oldTransport = mTransport;
if (oldTransport != null) {
oldTransport.releaseContentObserver();
mTransport = null;
}
return oldTransport;
}
}
/**
* Returns true if this observer is interested receiving self-change notifications.
*
* Subclasses should override this method to indicate whether the observer
* is interested in receiving notifications for changes that it made to the
* content itself.
*
* @return True if self-change notifications should be delivered to the observer.
*/
public boolean deliverSelfNotifications() {
return false;
}
/**
* This method is called when a content change occurs.
* <p>
* Subclasses should override this method to handle content changes.
* </p>
*
* @param selfChange True if this is a self-change notification.
*/
public void onChange(boolean selfChange) {
// Do nothing. Subclass should override.
}
/**
* This method is called when a content change occurs.
* Includes the changed content Uri when available.
* <p>
* Subclasses should override this method to handle content changes.
* To ensure correct operation on older versions of the framework that
* did not provide a Uri argument, applications should also implement
* the {@link #onChange(boolean)} overload of this method whenever they
* implement the {@link #onChange(boolean, Uri)} overload.
* </p><p>
* Example implementation:
* <pre><code>
* // Implement the onChange(boolean) method to delegate the change notification to
* // the onChange(boolean, Uri) method to ensure correct operation on older versions
* // of the framework that did not have the onChange(boolean, Uri) method.
* {@literal @Override}
* public void onChange(boolean selfChange) {
* onChange(selfChange, null);
* }
*
* // Implement the onChange(boolean, Uri) method to take advantage of the new Uri argument.
* {@literal @Override}
* public void onChange(boolean selfChange, Uri uri) {
* // Handle change.
* }
* </code></pre>
* </p>
*
* @param selfChange True if this is a self-change notification.
* @param uri The Uri of the changed content, or null if unknown.
*/
public void onChange(boolean selfChange, Uri uri) {
onChange(selfChange);
}
/**
* Dispatches a change notification to the observer. Includes the changed
* content Uri when available and also the user whose content changed.
*
* @param selfChange True if this is a self-change notification.
* @param uri The Uri of the changed content, or null if unknown.
* @param userId The user whose content changed. Can be either a specific
* user or {@link UserHandle#USER_ALL}.
*
* @hide
*/
public void onChange(boolean selfChange, Uri uri, int userId) {
onChange(selfChange, uri);
}
/**
* Dispatches a change notification to the observer.
* <p>
* If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
* then a call to the {@link #onChange} method is posted to the handler's message queue.
* Otherwise, the {@link #onChange} method is invoked immediately on this thread.
* </p>
*
* @param selfChange True if this is a self-change notification.
*
* @deprecated Use {@link #dispatchChange(boolean, Uri)} instead.
*/
@Deprecated
public final void dispatchChange(boolean selfChange) {
dispatchChange(selfChange, null);
}
/**
* Dispatches a change notification to the observer.
* Includes the changed content Uri when available.
* <p>
* If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
* then a call to the {@link #onChange} method is posted to the handler's message queue.
* Otherwise, the {@link #onChange} method is invoked immediately on this thread.
* </p>
*
* @param selfChange True if this is a self-change notification.
* @param uri The Uri of the changed content, or null if unknown.
*/
public final void dispatchChange(boolean selfChange, Uri uri) {
dispatchChange(selfChange, uri, UserHandle.getCallingUserId());
}
/**
* Dispatches a change notification to the observer. Includes the changed
* content Uri when available and also the user whose content changed.
* <p>
* If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
* then a call to the {@link #onChange} method is posted to the handler's message queue.
* Otherwise, the {@link #onChange} method is invoked immediately on this thread.
* </p>
*
* @param selfChange True if this is a self-change notification.
* @param uri The Uri of the changed content, or null if unknown.
* @param userId The user whose content changed.
*/
private void dispatchChange(boolean selfChange, Uri uri, int userId) {
if (mHandler == null) {
onChange(selfChange, uri, userId);
} else {
mHandler.post(new NotificationRunnable(selfChange, uri, userId));
}
}
private final class NotificationRunnable implements Runnable {
private final boolean mSelfChange;
private final Uri mUri;
private final int mUserId;
public NotificationRunnable(boolean selfChange, Uri uri, int userId) {
mSelfChange = selfChange;
mUri = uri;
mUserId = userId;
}
@Override
public void run() {
ContentObserver.this.onChange(mSelfChange, mUri, mUserId);
}
}
private static final class Transport extends IContentObserver.Stub {
private ContentObserver mContentObserver;
public Transport(ContentObserver contentObserver) {
mContentObserver = contentObserver;
}
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
ContentObserver contentObserver = mContentObserver;
if (contentObserver != null) {
contentObserver.dispatchChange(selfChange, uri, userId);
}
}
public void releaseContentObserver() {
mContentObserver = null;
}
}
}