introduce PlaylistObserver
This commit is contained in:
parent
d8b276d586
commit
eba6acabc2
@ -26,9 +26,8 @@ public class LibraryObserver {
|
|||||||
* by the receiver
|
* by the receiver
|
||||||
*/
|
*/
|
||||||
public enum Type {
|
public enum Type {
|
||||||
ANY, // Any type may have changed
|
SONG, // Change affected song entries
|
||||||
SONG, // Change only affected song entries
|
PLAYLIST, // Change affected playlists
|
||||||
PLAYLIST, // Change only affected playlists
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,9 +41,10 @@ public class LibraryObserver {
|
|||||||
* to be overriden by the registered observer.
|
* to be overriden by the registered observer.
|
||||||
*
|
*
|
||||||
* @param type one of LibraryObserver.Type
|
* @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.
|
* @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.
|
// NOOP, should be overriden.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,11 +324,15 @@ public class MediaLibrary {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcasts a change to all registered observers
|
* 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;
|
ArrayList<LibraryObserver> list = sLibraryObservers;
|
||||||
for (int i = list.size(); --i != -1; )
|
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) {
|
if (rows > 0) {
|
||||||
getBackend(context).cleanOrphanedEntries(true);
|
getBackend(context).cleanOrphanedEntries(true);
|
||||||
notifyObserver(LibraryObserver.Type.ANY, false);
|
notifyObserver(LibraryObserver.Type.SONG, id, false);
|
||||||
|
notifyObserver(LibraryObserver.Type.PLAYLIST, -1, false);
|
||||||
}
|
}
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
@ -389,7 +394,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(LibraryObserver.Type.PLAYLIST, false);
|
notifyObserver(LibraryObserver.Type.PLAYLIST, id, false);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,7 +412,7 @@ public class MediaLibrary {
|
|||||||
boolean removed = (rows > 0);
|
boolean removed = (rows > 0);
|
||||||
|
|
||||||
if (removed)
|
if (removed)
|
||||||
notifyObserver(LibraryObserver.Type.PLAYLIST, false);
|
notifyObserver(LibraryObserver.Type.PLAYLIST, id, false);
|
||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,7 +450,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(LibraryObserver.Type.PLAYLIST, false);
|
notifyObserver(LibraryObserver.Type.PLAYLIST, playlistId, false);
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,7 +466,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(LibraryObserver.Type.PLAYLIST, false);
|
notifyObserver(LibraryObserver.Type.PLAYLIST, -1, false);
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,8 +488,10 @@ public class MediaLibrary {
|
|||||||
removePlaylist(context, playlistId);
|
removePlaylist(context, playlistId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newId != -1)
|
if (newId != -1) {
|
||||||
notifyObserver(LibraryObserver.Type.PLAYLIST, false);
|
notifyObserver(LibraryObserver.Type.PLAYLIST, playlistId, false);
|
||||||
|
notifyObserver(LibraryObserver.Type.PLAYLIST, newId, false);
|
||||||
|
}
|
||||||
return newId;
|
return newId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,7 +536,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(LibraryObserver.Type.PLAYLIST, false);
|
notifyObserver(LibraryObserver.Type.PLAYLIST, playlistId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -205,7 +205,7 @@ public class MediaScanner implements Handler.Callback {
|
|||||||
|
|
||||||
switch (rpc) {
|
switch (rpc) {
|
||||||
case MSG_NOTIFY_CHANGE: {
|
case MSG_NOTIFY_CHANGE: {
|
||||||
MediaLibrary.notifyObserver(LibraryObserver.Type.SONG, true);
|
MediaLibrary.notifyObserver(LibraryObserver.Type.SONG, -1, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MSG_SCAN_FINISHED: {
|
case MSG_SCAN_FINISHED: {
|
||||||
@ -216,6 +216,8 @@ public class MediaScanner implements Handler.Callback {
|
|||||||
if (mPendingCleanup) {
|
if (mPendingCleanup) {
|
||||||
mPendingCleanup = false;
|
mPendingCleanup = false;
|
||||||
mBackend.cleanOrphanedEntries(true);
|
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.
|
// 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
|
// also signals that this will be our last update
|
||||||
// for this scan.
|
// for this scan.
|
||||||
mHandler.removeMessages(MSG_NOTIFY_CHANGE);
|
mHandler.removeMessages(MSG_NOTIFY_CHANGE);
|
||||||
MediaLibrary.notifyObserver(LibraryObserver.Type.ANY, false);
|
MediaLibrary.notifyObserver(LibraryObserver.Type.SONG, -1, false);
|
||||||
|
|
||||||
updateNotification(false);
|
updateNotification(false);
|
||||||
break;
|
break;
|
||||||
|
@ -431,6 +431,10 @@ public final class PlaybackService extends Service
|
|||||||
* Reference to precreated ReadAhead thread
|
* Reference to precreated ReadAhead thread
|
||||||
*/
|
*/
|
||||||
private ReadaheadThread mReadahead;
|
private ReadaheadThread mReadahead;
|
||||||
|
/**
|
||||||
|
* Referente to our playlist observer
|
||||||
|
*/
|
||||||
|
private PlaylistObserver mPlaylistObserver;
|
||||||
/**
|
/**
|
||||||
* Reference to precreated BASTP Object
|
* Reference to precreated BASTP Object
|
||||||
*/
|
*/
|
||||||
@ -502,6 +506,8 @@ public final class PlaybackService extends Service
|
|||||||
mRemoteControlClient = new RemoteControl().getClient(this);
|
mRemoteControlClient = new RemoteControl().getClient(this);
|
||||||
mRemoteControlClient.initializeRemote();
|
mRemoteControlClient.initializeRemote();
|
||||||
|
|
||||||
|
mPlaylistObserver = new PlaylistObserver();
|
||||||
|
|
||||||
mLooper = thread.getLooper();
|
mLooper = thread.getLooper();
|
||||||
mHandler = new Handler(mLooper, this);
|
mHandler = new Handler(mLooper, this);
|
||||||
|
|
||||||
@ -616,6 +622,7 @@ public final class PlaybackService extends Service
|
|||||||
enterSleepState();
|
enterSleepState();
|
||||||
|
|
||||||
MediaLibrary.unregisterLibraryObserver(mObserver);
|
MediaLibrary.unregisterLibraryObserver(mObserver);
|
||||||
|
mPlaylistObserver.unregister();
|
||||||
|
|
||||||
if (mMediaPlayer != null) {
|
if (mMediaPlayer != null) {
|
||||||
mMediaPlayer.release();
|
mMediaPlayer.release();
|
||||||
@ -1932,7 +1939,7 @@ public final class PlaybackService extends Service
|
|||||||
|
|
||||||
private final LibraryObserver mObserver = new LibraryObserver() {
|
private final LibraryObserver mObserver = new LibraryObserver() {
|
||||||
@Override
|
@Override
|
||||||
public void onChange(LibraryObserver.Type type, boolean ongoing)
|
public void onChange(LibraryObserver.Type type, long id, boolean ongoing)
|
||||||
{
|
{
|
||||||
MediaUtils.onMediaChange();
|
MediaUtils.onMediaChange();
|
||||||
onMediaChange();
|
onMediaChange();
|
||||||
|
@ -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?
|
||||||
|
}
|
@ -133,7 +133,7 @@ public class ScheduledLibraryUpdate extends JobService {
|
|||||||
*/
|
*/
|
||||||
private final LibraryObserver mObserver = new LibraryObserver() {
|
private final LibraryObserver mObserver = new LibraryObserver() {
|
||||||
@Override
|
@Override
|
||||||
public void onChange(LibraryObserver.Type type, boolean ongoing) {
|
public void onChange(LibraryObserver.Type type, long id, boolean ongoing) {
|
||||||
if (!ongoing) {
|
if (!ongoing) {
|
||||||
jobFinished(mJobParams, false);
|
jobFinished(mJobParams, false);
|
||||||
finalizeScan();
|
finalizeScan();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user