Allow registration of multiple content observers.

Also send a hint if this was an update due to a scan or not.
This commit is contained in:
Adrian Ulrich 2017-10-14 11:55:58 +02:00
parent b22a0424b8
commit 0c65294f7d
2 changed files with 36 additions and 28 deletions

View File

@ -97,7 +97,7 @@ public class MediaLibrary {
/** /**
* The observer to call-back during database changes * The observer to call-back during database changes
*/ */
private static ContentObserver sContentObserver; private static final ArrayList<ContentObserver> sContentObservers = new ArrayList<ContentObserver>(2);
/** /**
* The lock we are using during object creation * The lock we are using during object creation
*/ */
@ -264,14 +264,20 @@ public class MediaLibrary {
/** /**
* Registers a new content observer for the media library * Registers a new content observer for the media library
* *
* The MediaLibrary will call `onChange(boolean ongoing)` if
* the media library changed.
*
* `ongoing` will be set to `true` if you are expected to receive
* more updates soon. A value of `false` indicates that no
* scan is going on.
*
* @param observer the content observer we are going to call on changes * @param observer the content observer we are going to call on changes
*/ */
public static void registerContentObserver(ContentObserver observer) { public static void registerContentObserver(ContentObserver observer) {
if (sContentObserver == null) { if (sContentObservers.contains(observer))
sContentObserver = observer;
} else {
throw new IllegalStateException("ContentObserver was already registered"); throw new IllegalStateException("ContentObserver was already registered");
}
sContentObservers.add(observer);
} }
/** /**
@ -281,23 +287,19 @@ public class MediaLibrary {
* @param observer the content observer to unregister. * @param observer the content observer to unregister.
*/ */
public static void unregisterContentObserver(ContentObserver observer) { public static void unregisterContentObserver(ContentObserver observer) {
if (sContentObserver == null) boolean removed = sContentObservers.remove(observer);
throw new IllegalStateException("No ContentObserver was registered!");
if (!sContentObserver.equals(observer)) if (!removed)
throw new IllegalArgumentException("Passed content observer was not the one you registered!"); throw new IllegalArgumentException("This content observer was never registered!");
// Sanity check passed: unregister observer.
sContentObserver = null;
} }
/** /**
* Broadcasts a change to the observer, which will queue and dispatch * Broadcasts a change to all registered observers
* the event to any registered observer
*/ */
static void notifyObserver() { static void notifyObserver(boolean ongoing) {
if (sContentObserver != null) ArrayList<ContentObserver> list = sContentObservers;
sContentObserver.onChange(true); for (int i = list.size(); --i != -1; )
list.get(i).onChange(ongoing);
} }
/** /**
@ -326,7 +328,7 @@ public class MediaLibrary {
if (rows > 0) { if (rows > 0) {
getBackend(context).cleanOrphanedEntries(true); getBackend(context).cleanOrphanedEntries(true);
notifyObserver(); notifyObserver(false);
} }
return rows; return rows;
} }
@ -357,7 +359,7 @@ public class MediaLibrary {
long id = getBackend(context).insert(MediaLibrary.TABLE_PLAYLISTS, null, v); long id = getBackend(context).insert(MediaLibrary.TABLE_PLAYLISTS, null, v);
if (id != -1) if (id != -1)
notifyObserver(); notifyObserver(false);
return id; return id;
} }
@ -375,7 +377,7 @@ public class MediaLibrary {
boolean removed = (rows > 0); boolean removed = (rows > 0);
if (removed) if (removed)
notifyObserver(); notifyObserver(false);
return removed; return removed;
} }
@ -413,7 +415,7 @@ public class MediaLibrary {
int rows = getBackend(context).bulkInsert(MediaLibrary.TABLE_PLAYLISTS_SONGS, null, bulk); int rows = getBackend(context).bulkInsert(MediaLibrary.TABLE_PLAYLISTS_SONGS, null, bulk);
if (rows > 0) if (rows > 0)
notifyObserver(); notifyObserver(false);
return rows; return rows;
} }
@ -429,7 +431,7 @@ public class MediaLibrary {
int rows = getBackend(context).delete(MediaLibrary.TABLE_PLAYLISTS_SONGS, selection, selectionArgs); int rows = getBackend(context).delete(MediaLibrary.TABLE_PLAYLISTS_SONGS, selection, selectionArgs);
if (rows > 0) if (rows > 0)
notifyObserver(); notifyObserver(false);
return rows; return rows;
} }
@ -452,7 +454,7 @@ public class MediaLibrary {
} }
if (newId != -1) if (newId != -1)
notifyObserver(); notifyObserver(false);
return newId; return newId;
} }
@ -497,7 +499,7 @@ public class MediaLibrary {
selection = MediaLibrary.PlaylistSongColumns._ID+"="+from; selection = MediaLibrary.PlaylistSongColumns._ID+"="+from;
getBackend(context).update(MediaLibrary.TABLE_PLAYLISTS_SONGS, v, selection, null); getBackend(context).update(MediaLibrary.TABLE_PLAYLISTS_SONGS, v, selection, null);
notifyObserver(); notifyObserver(false);
} }
/** /**

View File

@ -195,7 +195,7 @@ public class MediaScanner implements Handler.Callback {
switch (rpc) { switch (rpc) {
case MSG_NOTIFY_CHANGE: { case MSG_NOTIFY_CHANGE: {
MediaLibrary.notifyObserver(); MediaLibrary.notifyObserver(true);
break; break;
} }
case MSG_SCAN_FINISHED: { case MSG_SCAN_FINISHED: {
@ -207,9 +207,15 @@ public class MediaScanner implements Handler.Callback {
mPendingCleanup = false; mPendingCleanup = false;
mBackend.cleanOrphanedEntries(true); mBackend.cleanOrphanedEntries(true);
} }
// make sure to notify about changes which cleanOrphanedEntries
// might have caused // Send a last change notification to all observers.
mHandler.sendEmptyMessage(MSG_NOTIFY_CHANGE); // This lets all consumers know about (possible)
// cleanups of orphaned files. The `false' value
// also signals that this will be our last update
// for this scan.
mHandler.removeMessages(MSG_NOTIFY_CHANGE);
MediaLibrary.notifyObserver(false);
updateNotification(false); updateNotification(false);
break; break;
} }