package android.content;
import java.util.ArrayList;
import android.database.ContentObserver;
import android.net.Uri;
import android.util.Log;
/**
* I make the content service be a singleton
* @author wenhaoli
*
*/
public class ContentService {
private static final String TAG = " ContentService<< ";
private static boolean DEBUG = true;
private Context mContext;
private static ContentService instance;
private final ObserverNode mRootNode = new ObserverNode("");
/*package*/ ContentService(Context context) {
mContext = context;
}
public static ContentService main(Context context) {
instance = new ContentService(context);
return instance;
}
public static ContentService getContentService(){
return instance;
}
public void registerContentObserver(Uri uri, boolean notifyForDescendents,
ContentObserver observer) {
if (observer == null || uri == null) {
throw new IllegalArgumentException("You must pass a valid uri and observer");
}
if(DEBUG){
System.out.println(TAG+"Register Content Observer...");
}
mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode);
}
public static final class ObserverCall {
final ObserverNode mNode;
final ContentObserver mObserver;
final boolean mSelfNotify;
ObserverCall(ObserverNode node, ContentObserver observer,
boolean selfNotify) {
mNode = node;
mObserver = observer;
mSelfNotify = selfNotify;
}
}
public void notifyChange(Uri uri, ContentObserver observer,
boolean observerWantsSelfNotifications, boolean syncToNetwork) {
if(DEBUG) System.out.println(TAG+"Notify change...");
ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
calls);
final int numCalls = calls.size();
for (int i=0; i<numCalls; i++) {
ObserverCall oc = calls.get(i);
try {
oc.mObserver.onChange(oc.mSelfNotify);
if (DEBUG) {
Log.v(TAG, "Notified " + oc.mObserver + " of " + "update at " + uri);
}
} catch (Exception ex) {
//Remove dead observers
final ArrayList<ObserverNode.ObserverEntry> list
= oc.mNode.mObservers;
int numList = list.size();
for (int j=0; j<numList; j++) {
ObserverNode.ObserverEntry oe = list.get(j);
if (oe.observer == oc.mObserver||oc.mObserver==null) {
list.remove(j);
j--;
numList--;
}
}
}
}
}
public static final class ObserverNode {
private String mName;
private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>();
private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();
private class ObserverEntry{
public final boolean notifyForDescendents;
public final ContentObserver observer;
ObserverEntry(ContentObserver o, boolean n, Object observersLock){
notifyForDescendents = n;
observer = o;
}
}
public ObserverNode(String name) {
mName = name;
}
private int countUriSegments(Uri uri) {
if (uri == null) {
return 0;
}
return uri.getPathSegments().size() + 1;
}
private String getUriSegment(Uri uri, int index) {
if (uri != null) {
if (index == 0) {
return uri.getAuthority();
} else {
return uri.getPathSegments().get(index - 1);
}
} else {
return null;
}
}
public void addObserverLocked(Uri uri, ContentObserver observer,
boolean notifyForDescendents, Object observersLock) {
addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock);
}
public boolean removeObserverLocked(ContentObserver observer) {
int size = mChildren.size();
for (int i = 0; i < size; i++) {
boolean empty = mChildren.get(i).removeObserverLocked(observer);
if (empty) {
mChildren.remove(i);
i--;
size--;
}
}
size = mObservers.size();
for (int i = 0; i < size; i++) {
ObserverEntry entry = mObservers.get(i);
if (entry.observer == observer) {
mObservers.remove(i);
break;
}
}
if (mChildren.size() == 0 && mObservers.size() == 0) {
return true;
}
return false;
}
private void addObserverLocked(Uri uri, int index, ContentObserver observer,
boolean notifyForDescendents, Object observersLock) {
// If this is the leaf node add the observer
if (index == countUriSegments(uri)) {
mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock));
return;
}
// Look to see if the proper child already exists
String segment = getUriSegment(uri, index);
if (segment == null) {
throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer");
}
int N = mChildren.size();
for (int i = 0; i < N; i++) {
ObserverNode node = mChildren.get(i);
if (node.mName.equals(segment)) {
node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock);
return;
}
}
// No child found, create one
ObserverNode node = new ObserverNode(segment);
mChildren.add(node);
node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock);
}
private void collectMyObserversLocked(boolean leaf, ContentObserver observer,
boolean selfNotify, ArrayList<ObserverCall> calls) {
int N = mObservers.size();
for (int i = 0; i < N; i++) {
ObserverEntry entry = mObservers.get(i);
// Don't notify the observer if it sent the notification and isn't interesed
// in self notifications
if (entry.observer== observer && !selfNotify) {
continue;
}
// Make sure the observer is interested in the notification
if (leaf || (!leaf && entry.notifyForDescendents)) {
calls.add(new ObserverCall(this, entry.observer, selfNotify));
}
}
}
public void collectObserversLocked(Uri uri, int index, ContentObserver observer,
boolean selfNotify, ArrayList<ObserverCall> calls){
String segment = null;
int segmentCount = countUriSegments(uri);
if (index >= segmentCount) {
// This is the leaf node, notify all observers
collectMyObserversLocked(true, observer, selfNotify, calls);
} else if (index < segmentCount){
segment = getUriSegment(uri, index);
// Notify any observers at this level who are interested in descendents
collectMyObserversLocked(false, observer, selfNotify, calls);
}
int N = mChildren.size();
for (int i = 0; i < N; i++) {
ObserverNode node = mChildren.get(i);
if (segment == null || node.mName.equals(segment)) {
// We found the child,
node.collectObserversLocked(uri, index + 1, observer, selfNotify, calls);
if (segment != null) {
break;
}
}
}
}
}
public void unregisterContentObserver(ContentObserver observer) {
if (observer == null) {
throw new IllegalArgumentException("You must pass a valid observer");
}
mRootNode.removeObserverLocked(observer);
if (DEBUG) Log.v(TAG, "Unregistered observer " + observer);
}
}