introduce PlaylistObserver

This commit is contained in:
Adrian Ulrich 2018-06-30 10:32:21 +02:00
parent d8b276d586
commit eba6acabc2
6 changed files with 114 additions and 18 deletions

View File

@ -26,9 +26,8 @@ public class LibraryObserver {
* by the receiver
*/
public enum Type {
ANY, // Any type may have changed
SONG, // Change only affected song entries
PLAYLIST, // Change only affected playlists
SONG, // Change affected song entries
PLAYLIST, // Change affected playlists
}
/**
@ -42,9 +41,10 @@ public class LibraryObserver {
* to be overriden by the registered observer.
*
* @param type one of LibraryObserver.Type
* @param id hint of which id changed for type, -1 if unspecified.
* @param ongoing whether or not to expect more events soon.
*/
public void onChange(Type type, boolean ongoing) {
public void onChange(Type type, long id, boolean ongoing) {
// NOOP, should be overriden.
}
}

View File

@ -324,11 +324,15 @@ public class MediaLibrary {
/**
* Broadcasts a change to all registered observers
*
* @param type the type of this event.
* @param id the id of type which changed, -1 if unknown
* @param ongoing whether or not to expect more of these updates soon
*/
static void notifyObserver(LibraryObserver.Type type, boolean ongoing) {
static void notifyObserver(LibraryObserver.Type type, long id, boolean ongoing) {
ArrayList<LibraryObserver> list = sLibraryObservers;
for (int i = list.size(); --i != -1; )
list.get(i).onChange(type, ongoing);
list.get(i).onChange(type, id, ongoing);
}
/**
@ -357,7 +361,8 @@ public class MediaLibrary {
if (rows > 0) {
getBackend(context).cleanOrphanedEntries(true);
notifyObserver(LibraryObserver.Type.ANY, false);
notifyObserver(LibraryObserver.Type.SONG, id, false);
notifyObserver(LibraryObserver.Type.PLAYLIST, -1, false);
}
return rows;
}
@ -389,7 +394,7 @@ public class MediaLibrary {
long id = getBackend(context).insert(MediaLibrary.TABLE_PLAYLISTS, null, v);
if (id != -1)
notifyObserver(LibraryObserver.Type.PLAYLIST, false);
notifyObserver(LibraryObserver.Type.PLAYLIST, id, false);
return id;
}
@ -407,7 +412,7 @@ public class MediaLibrary {
boolean removed = (rows > 0);
if (removed)
notifyObserver(LibraryObserver.Type.PLAYLIST, false);
notifyObserver(LibraryObserver.Type.PLAYLIST, id, false);
return removed;
}
@ -445,7 +450,7 @@ public class MediaLibrary {
int rows = getBackend(context).bulkInsert(MediaLibrary.TABLE_PLAYLISTS_SONGS, null, bulk);
if (rows > 0)
notifyObserver(LibraryObserver.Type.PLAYLIST, false);
notifyObserver(LibraryObserver.Type.PLAYLIST, playlistId, false);
return rows;
}
@ -461,7 +466,7 @@ public class MediaLibrary {
int rows = getBackend(context).delete(MediaLibrary.TABLE_PLAYLISTS_SONGS, selection, selectionArgs);
if (rows > 0)
notifyObserver(LibraryObserver.Type.PLAYLIST, false);
notifyObserver(LibraryObserver.Type.PLAYLIST, -1, false);
return rows;
}
@ -483,8 +488,10 @@ public class MediaLibrary {
removePlaylist(context, playlistId);
}
if (newId != -1)
notifyObserver(LibraryObserver.Type.PLAYLIST, false);
if (newId != -1) {
notifyObserver(LibraryObserver.Type.PLAYLIST, playlistId, false);
notifyObserver(LibraryObserver.Type.PLAYLIST, newId, false);
}
return newId;
}
@ -529,7 +536,7 @@ public class MediaLibrary {
selection = MediaLibrary.PlaylistSongColumns._ID+"="+from;
getBackend(context).update(MediaLibrary.TABLE_PLAYLISTS_SONGS, v, selection, null);
notifyObserver(LibraryObserver.Type.PLAYLIST, false);
notifyObserver(LibraryObserver.Type.PLAYLIST, playlistId, false);
}
/**

View File

@ -205,7 +205,7 @@ public class MediaScanner implements Handler.Callback {
switch (rpc) {
case MSG_NOTIFY_CHANGE: {
MediaLibrary.notifyObserver(LibraryObserver.Type.SONG, true);
MediaLibrary.notifyObserver(LibraryObserver.Type.SONG, -1, true);
break;
}
case MSG_SCAN_FINISHED: {
@ -216,6 +216,8 @@ public class MediaScanner implements Handler.Callback {
if (mPendingCleanup) {
mPendingCleanup = false;
mBackend.cleanOrphanedEntries(true);
// scan run possibly deleted file which may affect playlists:
MediaLibrary.notifyObserver(LibraryObserver.Type.PLAYLIST, -1, false);
}
// Send a last change notification to all observers.
@ -224,7 +226,7 @@ public class MediaScanner implements Handler.Callback {
// also signals that this will be our last update
// for this scan.
mHandler.removeMessages(MSG_NOTIFY_CHANGE);
MediaLibrary.notifyObserver(LibraryObserver.Type.ANY, false);
MediaLibrary.notifyObserver(LibraryObserver.Type.SONG, -1, false);
updateNotification(false);
break;

View File

@ -431,6 +431,10 @@ public final class PlaybackService extends Service
* Reference to precreated ReadAhead thread
*/
private ReadaheadThread mReadahead;
/**
* Referente to our playlist observer
*/
private PlaylistObserver mPlaylistObserver;
/**
* Reference to precreated BASTP Object
*/
@ -502,6 +506,8 @@ public final class PlaybackService extends Service
mRemoteControlClient = new RemoteControl().getClient(this);
mRemoteControlClient.initializeRemote();
mPlaylistObserver = new PlaylistObserver();
mLooper = thread.getLooper();
mHandler = new Handler(mLooper, this);
@ -616,6 +622,7 @@ public final class PlaybackService extends Service
enterSleepState();
MediaLibrary.unregisterLibraryObserver(mObserver);
mPlaylistObserver.unregister();
if (mMediaPlayer != null) {
mMediaPlayer.release();
@ -1932,7 +1939,7 @@ public final class PlaybackService extends Service
private final LibraryObserver mObserver = new LibraryObserver() {
@Override
public void onChange(LibraryObserver.Type type, boolean ongoing)
public void onChange(LibraryObserver.Type type, long id, boolean ongoing)
{
MediaUtils.onMediaChange();
onMediaChange();

View File

@ -0,0 +1,80 @@
/*
* Copyright (C) 2018 Adrian Ulrich <adrian@blinkenlights.ch>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ch.blinkenlights.android.vanilla;
import ch.blinkenlights.android.medialibrary.MediaLibrary;
import ch.blinkenlights.android.medialibrary.LibraryObserver;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.Process;
import java.io.File;
import android.util.Log;
public class PlaylistObserver implements Handler.Callback {
/**
* Handler thread used to perform playlist sync.
*/
private Handler mHandler;
/**
* Directory which holds observed playlists.
*/
private File mPlaylists = new File(Environment.getExternalStorageDirectory(), "Playlists");
public PlaylistObserver() {
// Create thread which will be used for background work.
HandlerThread handlerThread = new HandlerThread("PlaylistWriter", Process.THREAD_PRIORITY_LOWEST);
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper(), this);
// Register to receive media library events.
MediaLibrary.registerLibraryObserver(mObserver);
}
/**
* Unregisters this observer, the object must not be used anymore
* after this function was called.
*/
public void unregister() {
MediaLibrary.unregisterLibraryObserver(mObserver);
}
@Override
public boolean handleMessage(Message message) {
return true;
}
/**
* Library observer callback which notifies us about media library
* events.
*/
private final LibraryObserver mObserver = new LibraryObserver() {
@Override
public void onChange(LibraryObserver.Type type, long id, boolean ongoing) {
Log.v("VanillaMusic", "onChange type = "+type+", id = "+id+" ongoing = "+ongoing);
}
};
// TODO:
// Use FileObserver to track playlist changes?
// how do we check modifications? write a shadow-dir in private app storage with same mtimes?
}

View File

@ -133,7 +133,7 @@ public class ScheduledLibraryUpdate extends JobService {
*/
private final LibraryObserver mObserver = new LibraryObserver() {
@Override
public void onChange(LibraryObserver.Type type, boolean ongoing) {
public void onChange(LibraryObserver.Type type, long id, boolean ongoing) {
if (!ongoing) {
jobFinished(mJobParams, false);
finalizeScan();