mirror of
https://github.com/ultrasonic/ultrasonic
synced 2025-02-17 04:00:39 +01:00
Started to use Koin, refactored lifecycleSupport and Intent handling
This commit is contained in:
parent
13b987791e
commit
53628dde54
@ -38,6 +38,10 @@ import org.moire.ultrasonic.service.DownloadServiceImpl;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import kotlin.Lazy;
|
||||
|
||||
import static org.koin.java.standalone.KoinJavaComponent.inject;
|
||||
|
||||
/**
|
||||
* Equalizer controls.
|
||||
*
|
||||
@ -52,6 +56,8 @@ public class EqualizerActivity extends ResultActivity
|
||||
private EqualizerController equalizerController;
|
||||
private Equalizer equalizer;
|
||||
|
||||
private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle bundle)
|
||||
{
|
||||
@ -123,14 +129,7 @@ public class EqualizerActivity extends ResultActivity
|
||||
|
||||
private void setup()
|
||||
{
|
||||
DownloadService instance = DownloadServiceImpl.getInstance();
|
||||
|
||||
if (instance == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
equalizerController = instance.getEqualizerController();
|
||||
equalizerController = downloadServiceImpl.getValue().getEqualizerController();
|
||||
equalizer = equalizerController.getEqualizer();
|
||||
|
||||
initEqualizer();
|
||||
|
@ -36,6 +36,8 @@ import android.widget.TextView;
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.service.DownloadService;
|
||||
import org.moire.ultrasonic.service.DownloadServiceImpl;
|
||||
import org.moire.ultrasonic.service.DownloadServiceLifecycleSupport;
|
||||
import org.moire.ultrasonic.service.ExternalStorageMonitor;
|
||||
import org.moire.ultrasonic.service.MediaPlayerService;
|
||||
import org.moire.ultrasonic.service.MusicService;
|
||||
import org.moire.ultrasonic.service.MusicServiceFactory;
|
||||
@ -47,7 +49,10 @@ import org.moire.ultrasonic.util.Util;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import kotlin.Lazy;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.koin.java.standalone.KoinJavaComponent.inject;
|
||||
|
||||
public class MainActivity extends SubsonicTabActivity
|
||||
{
|
||||
@ -68,6 +73,8 @@ public class MainActivity extends SubsonicTabActivity
|
||||
private static boolean infoDialogDisplayed;
|
||||
private static boolean shouldUseId3;
|
||||
|
||||
private Lazy<DownloadServiceLifecycleSupport> lifecycleSupport = inject(DownloadServiceLifecycleSupport.class);
|
||||
|
||||
/**
|
||||
* Called when the activity is first created.
|
||||
*/
|
||||
@ -477,7 +484,7 @@ public class MainActivity extends SubsonicTabActivity
|
||||
|
||||
private void exit()
|
||||
{
|
||||
DownloadServiceImpl.getInstance().onCommand(new Intent(this, MediaPlayerService.class));
|
||||
lifecycleSupport.getValue().onDestroy();
|
||||
Util.unregisterMediaButtonEventReceiver(this);
|
||||
finish();
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ public class SelectPlaylistActivity extends SubsonicTabActivity implements Adapt
|
||||
List<Playlist> playlists = musicService.getPlaylists(refresh, SelectPlaylistActivity.this, this);
|
||||
|
||||
if (!Util.isOffline(SelectPlaylistActivity.this))
|
||||
new CacheCleaner(SelectPlaylistActivity.this, getDownloadService()).cleanPlaylists(playlists);
|
||||
new CacheCleaner(SelectPlaylistActivity.this).cleanPlaylists(playlists);
|
||||
return playlists;
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,6 @@ import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import android.util.Log;
|
||||
import android.view.*;
|
||||
@ -39,6 +38,7 @@ import android.widget.*;
|
||||
import net.simonvt.menudrawer.MenuDrawer;
|
||||
import net.simonvt.menudrawer.Position;
|
||||
import org.koin.java.standalone.KoinJavaComponent;
|
||||
import static org.koin.java.standalone.KoinJavaComponent.inject;
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory.Entry;
|
||||
@ -56,6 +56,8 @@ import java.io.PrintWriter;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import kotlin.Lazy;
|
||||
|
||||
/**
|
||||
* @author Sindre Mehus
|
||||
*/
|
||||
@ -74,6 +76,9 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
|
||||
private static final String STATE_ACTIVE_POSITION = "org.moire.ultrasonic.activePosition";
|
||||
private static final int DIALOG_ASK_FOR_SHARE_DETAILS = 102;
|
||||
|
||||
private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class);
|
||||
private Lazy<DownloadServiceLifecycleSupport> lifecycleSupport = inject(DownloadServiceLifecycleSupport.class);
|
||||
|
||||
public MenuDrawer menuDrawer;
|
||||
private int activePosition = 1;
|
||||
private int menuActiveViewId;
|
||||
@ -97,7 +102,6 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
|
||||
applyTheme();
|
||||
super.onCreate(bundle);
|
||||
|
||||
if (DownloadServiceImpl.getInstance() == null) new DownloadServiceImpl(getApplicationContext());
|
||||
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||
|
||||
if (bundle != null)
|
||||
@ -155,6 +159,8 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
|
||||
instance = this;
|
||||
|
||||
Util.registerMediaButtonEventReceiver(this);
|
||||
// Lifecycle support's constructor registers some event receivers so it should be created early
|
||||
lifecycleSupport.getValue();
|
||||
|
||||
// Make sure to update theme
|
||||
if (theme != null && !theme.equals(Util.getTheme(this)))
|
||||
@ -256,27 +262,22 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
|
||||
|
||||
if (nowPlayingView != null)
|
||||
{
|
||||
final DownloadService downloadService = DownloadServiceImpl.getInstance();
|
||||
PlayerState playerState = downloadServiceImpl.getValue().getPlayerState();
|
||||
|
||||
if (downloadService != null)
|
||||
if (playerState.equals(PlayerState.PAUSED) || playerState.equals(PlayerState.STARTED))
|
||||
{
|
||||
PlayerState playerState = downloadService.getPlayerState();
|
||||
DownloadFile file = downloadServiceImpl.getValue().getCurrentPlaying();
|
||||
|
||||
if (playerState.equals(PlayerState.PAUSED) || playerState.equals(PlayerState.STARTED))
|
||||
if (file != null)
|
||||
{
|
||||
DownloadFile file = downloadService.getCurrentPlaying();
|
||||
|
||||
if (file != null)
|
||||
{
|
||||
final Entry song = file.getSong();
|
||||
showNowPlaying(SubsonicTabActivity.this, downloadService, song, playerState);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hideNowPlaying();
|
||||
final Entry song = file.getSong();
|
||||
showNowPlaying(SubsonicTabActivity.this, downloadServiceImpl.getValue(), song, playerState);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hideNowPlaying();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -763,18 +764,7 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
|
||||
|
||||
public DownloadService getDownloadService()
|
||||
{
|
||||
DownloadService downloadService = DownloadServiceImpl.getInstance();
|
||||
|
||||
if (downloadService != null)
|
||||
{
|
||||
return downloadService;
|
||||
}
|
||||
|
||||
Log.w(TAG, "DownloadService not running. Attempting to start it.");
|
||||
|
||||
new DownloadServiceImpl(getApplicationContext());
|
||||
|
||||
return DownloadServiceImpl.getInstance();
|
||||
return downloadServiceImpl.getValue();
|
||||
}
|
||||
|
||||
protected void warnIfNetworkOrStorageUnavailable()
|
||||
|
@ -22,6 +22,10 @@ import org.moire.ultrasonic.util.*;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import kotlin.Lazy;
|
||||
|
||||
import static org.koin.java.standalone.KoinJavaComponent.inject;
|
||||
|
||||
/**
|
||||
* Shows main app settings.
|
||||
*/
|
||||
@ -62,6 +66,8 @@ public class SettingsFragment extends PreferenceFragment
|
||||
private SharedPreferences settings;
|
||||
private int activeServers;
|
||||
|
||||
private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class);
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@ -401,7 +407,6 @@ public class SettingsFragment extends PreferenceFragment
|
||||
}
|
||||
|
||||
// Clear download queue.
|
||||
DownloadService downloadService = DownloadServiceImpl.getInstance();
|
||||
downloadService.clear();
|
||||
downloadServiceImpl.getValue().clear();
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,7 @@ import org.moire.ultrasonic.activity.DownloadActivity;
|
||||
import org.moire.ultrasonic.activity.MainActivity;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory;
|
||||
import org.moire.ultrasonic.service.DownloadService;
|
||||
import org.moire.ultrasonic.service.DownloadServiceImpl;
|
||||
import org.moire.ultrasonic.service.MediaPlayerService;
|
||||
import org.moire.ultrasonic.util.Constants;
|
||||
import org.moire.ultrasonic.util.FileUtil;
|
||||
|
||||
public class UltraSonicAppWidgetProvider extends AppWidgetProvider
|
||||
@ -194,27 +193,27 @@ public class UltraSonicAppWidgetProvider extends AppWidgetProvider
|
||||
Intent intent = new Intent(context, playerActive ? DownloadActivity.class : MainActivity.class);
|
||||
intent.setAction("android.intent.action.MAIN");
|
||||
intent.addCategory("android.intent.category.LAUNCHER");
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 10, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
views.setOnClickPendingIntent(R.id.appwidget_coverart, pendingIntent);
|
||||
views.setOnClickPendingIntent(R.id.appwidget_top, pendingIntent);
|
||||
|
||||
// Emulate media button clicks.
|
||||
intent = new Intent("1");
|
||||
intent.setComponent(new ComponentName(context, MediaPlayerService.class));
|
||||
intent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
intent.setPackage(context.getPackageName());
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
pendingIntent = PendingIntent.getBroadcast(context, 11, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.control_play, pendingIntent);
|
||||
|
||||
intent = new Intent("2"); // Use a unique action name to ensure a different PendingIntent to be created.
|
||||
intent.setComponent(new ComponentName(context, MediaPlayerService.class));
|
||||
intent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
intent.setPackage(context.getPackageName());
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
pendingIntent = PendingIntent.getBroadcast(context, 12, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.control_next, pendingIntent);
|
||||
|
||||
intent = new Intent("3"); // Use a unique action name to ensure a different PendingIntent to be created.
|
||||
intent.setComponent(new ComponentName(context, MediaPlayerService.class));
|
||||
intent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
intent.setPackage(context.getPackageName());
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PREVIOUS));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
pendingIntent = PendingIntent.getBroadcast(context, 13, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.control_previous, pendingIntent);
|
||||
}
|
||||
}
|
||||
|
@ -8,28 +8,24 @@ import org.moire.ultrasonic.domain.MusicDirectory.Entry;
|
||||
import org.moire.ultrasonic.service.DownloadService;
|
||||
import org.moire.ultrasonic.service.DownloadServiceImpl;
|
||||
|
||||
import kotlin.Lazy;
|
||||
|
||||
import static org.koin.java.standalone.KoinJavaComponent.inject;
|
||||
|
||||
public class A2dpIntentReceiver extends BroadcastReceiver
|
||||
{
|
||||
|
||||
private static final String PLAYSTATUS_RESPONSE = "com.android.music.playstatusresponse";
|
||||
private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class);
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
|
||||
DownloadService downloadService = DownloadServiceImpl.getInstance();
|
||||
|
||||
if (downloadService == null)
|
||||
if (downloadServiceImpl.getValue().getCurrentPlaying() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (downloadService.getCurrentPlaying() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Entry song = downloadService.getCurrentPlaying().getSong();
|
||||
Entry song = downloadServiceImpl.getValue().getCurrentPlaying().getSong();
|
||||
|
||||
if (song == null)
|
||||
{
|
||||
@ -39,8 +35,8 @@ public class A2dpIntentReceiver extends BroadcastReceiver
|
||||
Intent avrcpIntent = new Intent(PLAYSTATUS_RESPONSE);
|
||||
|
||||
Integer duration = song.getDuration();
|
||||
Integer playerPosition = downloadService.getPlayerPosition();
|
||||
Integer listSize = downloadService.getDownloads().size();
|
||||
Integer playerPosition = downloadServiceImpl.getValue().getPlayerPosition();
|
||||
Integer listSize = downloadServiceImpl.getValue().getDownloads().size();
|
||||
|
||||
if (duration != null)
|
||||
{
|
||||
@ -50,7 +46,7 @@ public class A2dpIntentReceiver extends BroadcastReceiver
|
||||
avrcpIntent.putExtra("position", (long) playerPosition);
|
||||
avrcpIntent.putExtra("ListSize", (long) listSize);
|
||||
|
||||
switch (downloadService.getPlayerState())
|
||||
switch (downloadServiceImpl.getValue().getPlayerState())
|
||||
{
|
||||
case STARTED:
|
||||
avrcpIntent.putExtra("playing", true);
|
||||
|
@ -24,7 +24,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import org.moire.ultrasonic.service.DownloadServiceImpl;
|
||||
import org.moire.ultrasonic.util.Constants;
|
||||
import org.moire.ultrasonic.util.Util;
|
||||
|
||||
/**
|
||||
@ -71,7 +71,7 @@ public class BluetoothIntentReceiver extends BroadcastReceiver
|
||||
if (disconnected)
|
||||
{
|
||||
Log.i(TAG, "Disconnected from Bluetooth device, requesting pause.");
|
||||
context.sendBroadcast(new Intent(DownloadServiceImpl.CMD_PAUSE));
|
||||
context.sendBroadcast(new Intent(Constants.CMD_PAUSE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,22 +21,25 @@ package org.moire.ultrasonic.receiver;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
|
||||
import org.moire.ultrasonic.service.DownloadServiceImpl;
|
||||
import org.moire.ultrasonic.service.MediaPlayerService;
|
||||
import org.moire.ultrasonic.service.DownloadServiceLifecycleSupport;
|
||||
import org.moire.ultrasonic.util.Constants;
|
||||
import org.moire.ultrasonic.util.Util;
|
||||
|
||||
import kotlin.Lazy;
|
||||
|
||||
import static org.koin.java.standalone.KoinJavaComponent.inject;
|
||||
|
||||
/**
|
||||
* @author Sindre Mehus
|
||||
*/
|
||||
public class MediaButtonIntentReceiver extends BroadcastReceiver
|
||||
{
|
||||
|
||||
private static final String TAG = MediaButtonIntentReceiver.class.getSimpleName();
|
||||
private Lazy<DownloadServiceLifecycleSupport> lifecycleSupport = inject(DownloadServiceLifecycleSupport.class);
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent)
|
||||
@ -57,23 +60,17 @@ public class MediaButtonIntentReceiver extends BroadcastReceiver
|
||||
Parcelable event = (Parcelable) extras.get(Intent.EXTRA_KEY_EVENT);
|
||||
Log.i(TAG, "Got MEDIA_BUTTON key event: " + event);
|
||||
|
||||
Intent serviceIntent = new Intent(context, MediaPlayerService.class);
|
||||
serviceIntent.putExtra(Intent.EXTRA_KEY_EVENT, event);
|
||||
|
||||
try
|
||||
{
|
||||
if (DownloadServiceImpl.getInstance() == null) new DownloadServiceImpl(context);
|
||||
DownloadServiceImpl.getInstance().onCommand(serviceIntent);
|
||||
Intent serviceIntent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
serviceIntent.putExtra(Intent.EXTRA_KEY_EVENT, event);
|
||||
lifecycleSupport.getValue().receiveIntent(serviceIntent);
|
||||
|
||||
if (isOrderedBroadcast())
|
||||
{
|
||||
abortBroadcast();
|
||||
}
|
||||
}
|
||||
catch (IllegalStateException exception)
|
||||
{
|
||||
Log.w(TAG, "MediaButtonIntentReceiver couldn't start DownloadServiceImpl because the application was in the background.");
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
// Ignored.
|
||||
|
@ -0,0 +1,6 @@
|
||||
package org.moire.ultrasonic.service;
|
||||
|
||||
public abstract class Consumer<T>
|
||||
{
|
||||
public abstract void accept(T t);
|
||||
}
|
@ -37,11 +37,13 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import kotlin.Lazy;
|
||||
import kotlin.Pair;
|
||||
|
||||
import static android.content.Context.POWER_SERVICE;
|
||||
import static android.os.PowerManager.ON_AFTER_RELEASE;
|
||||
import static android.os.PowerManager.SCREEN_DIM_WAKE_LOCK;
|
||||
import static org.koin.java.standalone.KoinJavaComponent.inject;
|
||||
|
||||
/**
|
||||
* @author Sindre Mehus
|
||||
@ -439,7 +441,7 @@ public class DownloadFile
|
||||
wifiLock.release();
|
||||
}
|
||||
|
||||
new CacheCleaner(context, DownloadServiceImpl.getInstance()).cleanSpace();
|
||||
new CacheCleaner(context).cleanSpace();
|
||||
|
||||
MediaPlayerService.checkDownloads(context);
|
||||
}
|
||||
|
@ -0,0 +1,105 @@
|
||||
package org.moire.ultrasonic.service;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import org.moire.ultrasonic.util.Constants;
|
||||
import org.moire.ultrasonic.util.FileUtil;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class DownloadQueueSerializer
|
||||
{
|
||||
private static final String TAG = DownloadQueueSerializer.class.getSimpleName();
|
||||
|
||||
public final Lock lock = new ReentrantLock();
|
||||
public final AtomicBoolean setup = new AtomicBoolean(false);
|
||||
private Context context;
|
||||
|
||||
public DownloadQueueSerializer(Context context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void serializeDownloadQueue(Iterable<DownloadFile> songs, int currentPlayingIndex, int currentPlayingPosition)
|
||||
{
|
||||
if (!setup.get())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
new SerializeTask().execute(songs, currentPlayingIndex, currentPlayingPosition);
|
||||
}
|
||||
|
||||
public void serializeDownloadQueueNow(Iterable<DownloadFile> songs, int currentPlayingIndex, int currentPlayingPosition)
|
||||
{
|
||||
State state = new State();
|
||||
for (DownloadFile downloadFile : songs)
|
||||
{
|
||||
state.songs.add(downloadFile.getSong());
|
||||
}
|
||||
state.currentPlayingIndex = currentPlayingIndex;
|
||||
state.currentPlayingPosition = currentPlayingPosition;
|
||||
|
||||
Log.i(TAG, String.format("Serialized currentPlayingIndex: %d, currentPlayingPosition: %d", state.currentPlayingIndex, state.currentPlayingPosition));
|
||||
FileUtil.serialize(context, state, Constants.FILENAME_DOWNLOADS_SER);
|
||||
}
|
||||
|
||||
public void deserializeDownloadQueue(Consumer<State> afterDeserialized)
|
||||
{
|
||||
new DeserializeTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, afterDeserialized);
|
||||
}
|
||||
|
||||
public void deserializeDownloadQueueNow(Consumer<State> afterDeserialized)
|
||||
{
|
||||
State state = FileUtil.deserialize(context, Constants.FILENAME_DOWNLOADS_SER);
|
||||
if (state == null) return;
|
||||
Log.i(TAG, "Deserialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition);
|
||||
afterDeserialized.accept(state);
|
||||
}
|
||||
|
||||
private class SerializeTask extends AsyncTask<Object, Void, Void>
|
||||
{
|
||||
@Override
|
||||
protected Void doInBackground(Object... params)
|
||||
{
|
||||
if (lock.tryLock())
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.currentThread().setName("SerializeTask");
|
||||
serializeDownloadQueueNow((Iterable<DownloadFile>)params[0], (int)params[1], (int)params[2]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class DeserializeTask extends AsyncTask<Object, Void, Void>
|
||||
{
|
||||
@Override
|
||||
protected Void doInBackground(Object... params)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.currentThread().setName("DeserializeTask");
|
||||
lock.lock();
|
||||
deserializeDownloadQueueNow((Consumer<State>)params[0]);
|
||||
setup.set(true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -20,7 +20,6 @@ package org.moire.ultrasonic.service;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.PowerManager;
|
||||
import android.util.Log;
|
||||
|
||||
import org.koin.java.standalone.KoinJavaComponent;
|
||||
@ -42,6 +41,9 @@ import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import kotlin.Lazy;
|
||||
|
||||
import static org.koin.java.standalone.KoinJavaComponent.inject;
|
||||
import static org.moire.ultrasonic.service.MediaPlayerService.playerState;
|
||||
|
||||
/**
|
||||
@ -52,26 +54,18 @@ public class DownloadServiceImpl implements DownloadService
|
||||
{
|
||||
private static final String TAG = DownloadServiceImpl.class.getSimpleName();
|
||||
|
||||
public static final String CMD_PLAY = "org.moire.ultrasonic.CMD_PLAY";
|
||||
public static final String CMD_TOGGLEPAUSE = "org.moire.ultrasonic.CMD_TOGGLEPAUSE";
|
||||
public static final String CMD_PAUSE = "org.moire.ultrasonic.CMD_PAUSE";
|
||||
public static final String CMD_STOP = "org.moire.ultrasonic.CMD_STOP";
|
||||
public static final String CMD_PREVIOUS = "org.moire.ultrasonic.CMD_PREVIOUS";
|
||||
public static final String CMD_NEXT = "org.moire.ultrasonic.CMD_NEXT";
|
||||
private final LRUCache<MusicDirectory.Entry, DownloadFile> downloadFileCache = new LRUCache<>(100);
|
||||
|
||||
private DownloadServiceLifecycleSupport lifecycleSupport;
|
||||
|
||||
private final LRUCache<MusicDirectory.Entry, DownloadFile> downloadFileCache = new LRUCache<MusicDirectory.Entry, DownloadFile>(100);
|
||||
|
||||
private static DownloadServiceImpl instance;
|
||||
private String suggestedPlaylistName;
|
||||
private boolean keepScreenOn;
|
||||
|
||||
private boolean showVisualization;
|
||||
private boolean jukeboxEnabled;
|
||||
private boolean autoPlayStart;
|
||||
|
||||
private Context context;
|
||||
public Lazy<JukeboxService> jukeboxService = inject(JukeboxService.class);
|
||||
private Lazy<DownloadQueueSerializer> downloadQueueSerializer = inject(DownloadQueueSerializer.class);
|
||||
private Lazy<ExternalStorageMonitor> externalStorageMonitor = inject(ExternalStorageMonitor.class);
|
||||
|
||||
public DownloadServiceImpl(Context context)
|
||||
{
|
||||
@ -79,25 +73,152 @@ public class DownloadServiceImpl implements DownloadService
|
||||
|
||||
// TODO: refactor
|
||||
MediaPlayerService.shufflePlayBuffer = new ShufflePlayBuffer(context);
|
||||
MediaPlayerService.jukeboxService = new JukeboxService(context, this);
|
||||
externalStorageMonitor.getValue().onCreate(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
reset();
|
||||
}
|
||||
});
|
||||
|
||||
instance = this;
|
||||
lifecycleSupport = new DownloadServiceLifecycleSupport(context,this);
|
||||
lifecycleSupport.onCreate();
|
||||
MediaPlayerService.lifecycleSupport = lifecycleSupport;
|
||||
int instance = Util.getActiveServer(context);
|
||||
setJukeboxEnabled(Util.getJukeboxEnabled(context, instance));
|
||||
|
||||
Log.i(TAG, "DownloadServiceImpl created");
|
||||
}
|
||||
|
||||
public void onCommand(Intent intent)
|
||||
public void onDestroy()
|
||||
{
|
||||
lifecycleSupport.onStart(intent);
|
||||
Log.i(TAG, "DownloadServiceImpl received intent");
|
||||
externalStorageMonitor.getValue().onDestroy();
|
||||
context.stopService(new Intent(context, MediaPlayerService.class));
|
||||
Log.i(TAG, "DownloadServiceImpl destroyed");
|
||||
}
|
||||
|
||||
public static DownloadServiceImpl getInstance()
|
||||
private void executeOnStartedMediaPlayerService(final Consumer<MediaPlayerService> taskToExecute)
|
||||
{
|
||||
return instance;
|
||||
Thread t = new Thread()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
MediaPlayerService instance = MediaPlayerService.getInstance(context);
|
||||
taskToExecute.accept(instance);
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restore(List<MusicDirectory.Entry> songs, final int currentPlayingIndex, final int currentPlayingPosition, final boolean autoPlay, boolean newPlaylist)
|
||||
{
|
||||
download(songs, false, false, false, false, newPlaylist);
|
||||
|
||||
if (currentPlayingIndex != -1)
|
||||
{
|
||||
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() {
|
||||
@Override
|
||||
public void accept(MediaPlayerService mediaPlayerService) {
|
||||
mediaPlayerService.play(currentPlayingIndex, autoPlayStart);
|
||||
}
|
||||
});
|
||||
|
||||
if (MediaPlayerService.currentPlaying != null)
|
||||
{
|
||||
if (autoPlay && jukeboxService.getValue().isEnabled())
|
||||
{
|
||||
jukeboxService.getValue().skip(getCurrentPlayingIndex(), currentPlayingPosition / 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MediaPlayerService.currentPlaying.isCompleteFileAvailable())
|
||||
{
|
||||
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() {
|
||||
@Override
|
||||
public void accept(MediaPlayerService mediaPlayerService) {
|
||||
mediaPlayerService.doPlay(MediaPlayerService.currentPlaying, currentPlayingPosition, autoPlay);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
autoPlayStart = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void play(final int index)
|
||||
{
|
||||
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() {
|
||||
@Override
|
||||
public void accept(MediaPlayerService mediaPlayerService) {
|
||||
mediaPlayerService.play(index, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public synchronized void play()
|
||||
{
|
||||
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() {
|
||||
@Override
|
||||
public void accept(MediaPlayerService mediaPlayerService) {
|
||||
mediaPlayerService.play();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void togglePlayPause()
|
||||
{
|
||||
if (playerState == PlayerState.IDLE) autoPlayStart = true;
|
||||
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() {
|
||||
@Override
|
||||
public void accept(MediaPlayerService mediaPlayerService) {
|
||||
mediaPlayerService.togglePlayPause();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void seekTo(final int position)
|
||||
{
|
||||
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() {
|
||||
@Override
|
||||
public void accept(MediaPlayerService mediaPlayerService) {
|
||||
mediaPlayerService.seekTo(position);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void pause()
|
||||
{
|
||||
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() {
|
||||
@Override
|
||||
public void accept(MediaPlayerService mediaPlayerService) {
|
||||
mediaPlayerService.pause();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void start()
|
||||
{
|
||||
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() {
|
||||
@Override
|
||||
public void accept(MediaPlayerService mediaPlayerService) {
|
||||
mediaPlayerService.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void stop()
|
||||
{
|
||||
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() {
|
||||
@Override
|
||||
public void accept(MediaPlayerService mediaPlayerService) {
|
||||
mediaPlayerService.stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -129,8 +250,6 @@ public class DownloadServiceImpl implements DownloadService
|
||||
MediaPlayerService.downloadList.add(getCurrentPlayingIndex() + offset, downloadFile);
|
||||
offset++;
|
||||
}
|
||||
|
||||
MediaPlayerService.revision++;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -149,10 +268,10 @@ public class DownloadServiceImpl implements DownloadService
|
||||
if (mediaPlayerService != null) mediaPlayerService.setNextPlaying();
|
||||
}
|
||||
|
||||
MediaPlayerService.revision++;
|
||||
}
|
||||
MediaPlayerService.revision++;
|
||||
|
||||
MediaPlayerService.updateJukeboxPlaylist();
|
||||
jukeboxService.getValue().updatePlaylist();
|
||||
|
||||
if (shuffle) shuffle();
|
||||
|
||||
@ -171,7 +290,7 @@ public class DownloadServiceImpl implements DownloadService
|
||||
MediaPlayerService.checkDownloads(context);
|
||||
}
|
||||
|
||||
lifecycleSupport.serializeDownloadQueue();
|
||||
downloadQueueSerializer.getValue().serializeDownloadQueue(getSongs(), getCurrentPlayingIndex(), getPlayerPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -186,35 +305,7 @@ public class DownloadServiceImpl implements DownloadService
|
||||
MediaPlayerService.revision++;
|
||||
|
||||
MediaPlayerService.checkDownloads(context);
|
||||
lifecycleSupport.serializeDownloadQueue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restore(List<MusicDirectory.Entry> songs, int currentPlayingIndex, int currentPlayingPosition, boolean autoPlay, boolean newPlaylist)
|
||||
{
|
||||
download(songs, false, false, false, false, newPlaylist);
|
||||
|
||||
if (currentPlayingIndex != -1)
|
||||
{
|
||||
MediaPlayerService.getInstance(context).play(currentPlayingIndex, autoPlayStart);
|
||||
|
||||
if (MediaPlayerService.currentPlaying != null)
|
||||
{
|
||||
if (autoPlay && jukeboxEnabled)
|
||||
{
|
||||
MediaPlayerService.jukeboxService.skip(getCurrentPlayingIndex(), currentPlayingPosition / 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MediaPlayerService.currentPlaying.isCompleteFileAvailable())
|
||||
{
|
||||
MediaPlayerService.getInstance(context).doPlay(MediaPlayerService.currentPlaying, currentPlayingPosition, autoPlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
autoPlayStart = false;
|
||||
}
|
||||
downloadQueueSerializer.getValue().serializeDownloadQueue(getSongs(), getCurrentPlayingIndex(), getPlayerPosition());
|
||||
}
|
||||
|
||||
public synchronized void setCurrentPlaying(DownloadFile currentPlaying)
|
||||
@ -238,13 +329,13 @@ public class DownloadServiceImpl implements DownloadService
|
||||
@Override
|
||||
public void stopJukeboxService()
|
||||
{
|
||||
MediaPlayerService.jukeboxService.stopJukeboxService();
|
||||
jukeboxService.getValue().stopJukeboxService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startJukeboxService()
|
||||
{
|
||||
MediaPlayerService.jukeboxService.startJukeboxService();
|
||||
jukeboxService.getValue().startJukeboxService();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -274,8 +365,8 @@ public class DownloadServiceImpl implements DownloadService
|
||||
MediaPlayerService.downloadList.add(0, MediaPlayerService.currentPlaying);
|
||||
}
|
||||
MediaPlayerService.revision++;
|
||||
lifecycleSupport.serializeDownloadQueue();
|
||||
MediaPlayerService.updateJukeboxPlaylist();
|
||||
downloadQueueSerializer.getValue().serializeDownloadQueue(getSongs(), getCurrentPlayingIndex(), getPlayerPosition());
|
||||
jukeboxService.getValue().updatePlaylist();
|
||||
|
||||
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
|
||||
if (mediaPlayerService != null) mediaPlayerService.setNextPlaying();
|
||||
@ -349,12 +440,17 @@ public class DownloadServiceImpl implements DownloadService
|
||||
@Override
|
||||
public synchronized void clear()
|
||||
{
|
||||
MediaPlayerService.clear(true);
|
||||
clear(true);
|
||||
}
|
||||
|
||||
public synchronized void clear(boolean serialize)
|
||||
{
|
||||
MediaPlayerService.clear(serialize);
|
||||
jukeboxService.getValue().updatePlaylist();
|
||||
if (serialize)
|
||||
{
|
||||
downloadQueueSerializer.getValue().serializeDownloadQueue(getSongs(), getCurrentPlayingIndex(), getPlayerPosition());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -383,8 +479,8 @@ public class DownloadServiceImpl implements DownloadService
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleSupport.serializeDownloadQueue();
|
||||
MediaPlayerService.updateJukeboxPlaylist();
|
||||
downloadQueueSerializer.getValue().serializeDownloadQueue(getSongs(), getCurrentPlayingIndex(), getPlayerPosition());
|
||||
jukeboxService.getValue().updatePlaylist();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -415,8 +511,8 @@ public class DownloadServiceImpl implements DownloadService
|
||||
MediaPlayerService.downloadList.remove(downloadFile);
|
||||
MediaPlayerService.backgroundDownloadList.remove(downloadFile);
|
||||
MediaPlayerService.revision++;
|
||||
lifecycleSupport.serializeDownloadQueue();
|
||||
MediaPlayerService.updateJukeboxPlaylist();
|
||||
downloadQueueSerializer.getValue().serializeDownloadQueue(getSongs(), getCurrentPlayingIndex(), getPlayerPosition());
|
||||
jukeboxService.getValue().updatePlaylist();
|
||||
if (downloadFile == MediaPlayerService.nextPlaying)
|
||||
{
|
||||
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
|
||||
@ -461,10 +557,7 @@ public class DownloadServiceImpl implements DownloadService
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DownloadFile> getSongs()
|
||||
{
|
||||
return MediaPlayerService.downloadList;
|
||||
}
|
||||
public List<DownloadFile> getSongs() { return MediaPlayerService.downloadList; }
|
||||
|
||||
@Override
|
||||
public long getDownloadListDuration()
|
||||
@ -495,7 +588,7 @@ public class DownloadServiceImpl implements DownloadService
|
||||
@Override
|
||||
public synchronized List<DownloadFile> getDownloads()
|
||||
{
|
||||
List<DownloadFile> temp = new ArrayList<DownloadFile>();
|
||||
List<DownloadFile> temp = new ArrayList<>();
|
||||
temp.addAll(MediaPlayerService.downloadList);
|
||||
temp.addAll(MediaPlayerService.backgroundDownloadList);
|
||||
return temp;
|
||||
@ -507,33 +600,6 @@ public class DownloadServiceImpl implements DownloadService
|
||||
return MediaPlayerService.backgroundDownloadList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void play(int index)
|
||||
{
|
||||
MediaPlayerService.getInstance(context).play(index, true);
|
||||
}
|
||||
|
||||
public synchronized void play()
|
||||
{
|
||||
MediaPlayerService.getInstance(context).play();
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays or resumes the playback, depending on the current player state.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void togglePlayPause()
|
||||
{
|
||||
if (playerState == PlayerState.IDLE) autoPlayStart = true;
|
||||
MediaPlayerService.getInstance(context).togglePlayPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void seekTo(int position)
|
||||
{
|
||||
MediaPlayerService.getInstance(context).seekTo(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void previous()
|
||||
{
|
||||
@ -564,24 +630,6 @@ public class DownloadServiceImpl implements DownloadService
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void pause()
|
||||
{
|
||||
MediaPlayerService.getInstance(context).pause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void stop()
|
||||
{
|
||||
MediaPlayerService.getInstance(context).stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void start()
|
||||
{
|
||||
MediaPlayerService.getInstance(context).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reset()
|
||||
{
|
||||
@ -659,18 +707,16 @@ public class DownloadServiceImpl implements DownloadService
|
||||
@Override
|
||||
public boolean isJukeboxEnabled()
|
||||
{
|
||||
return jukeboxEnabled;
|
||||
return jukeboxService.getValue().isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJukeboxAvailable()
|
||||
{
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(context);
|
||||
|
||||
try
|
||||
{
|
||||
String username = Util.getUserName(context, Util.getActiveServer(context));
|
||||
UserInfo user = musicService.getUser(username, context, null);
|
||||
UserInfo user = MusicServiceFactory.getMusicService(context).getUser(username, context, null);
|
||||
return user.getJukeboxRole();
|
||||
}
|
||||
catch (Exception e)
|
||||
@ -684,12 +730,10 @@ public class DownloadServiceImpl implements DownloadService
|
||||
@Override
|
||||
public boolean isSharingAvailable()
|
||||
{
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(context);
|
||||
|
||||
try
|
||||
{
|
||||
String username = Util.getUserName(context, Util.getActiveServer(context));
|
||||
UserInfo user = musicService.getUser(username, context, null);
|
||||
UserInfo user = MusicServiceFactory.getMusicService(context).getUser(username, context, null);
|
||||
return user.getShareRole();
|
||||
}
|
||||
catch (Exception e)
|
||||
@ -703,12 +747,12 @@ public class DownloadServiceImpl implements DownloadService
|
||||
@Override
|
||||
public void setJukeboxEnabled(boolean jukeboxEnabled)
|
||||
{
|
||||
this.jukeboxEnabled = jukeboxEnabled;
|
||||
MediaPlayerService.jukeboxService.setEnabled(jukeboxEnabled);
|
||||
jukeboxService.getValue().setEnabled(jukeboxEnabled);
|
||||
setPlayerState(PlayerState.IDLE);
|
||||
|
||||
if (jukeboxEnabled)
|
||||
{
|
||||
MediaPlayerService.jukeboxService.startJukeboxService();
|
||||
jukeboxService.getValue().startJukeboxService();
|
||||
|
||||
reset();
|
||||
|
||||
@ -720,14 +764,14 @@ public class DownloadServiceImpl implements DownloadService
|
||||
}
|
||||
else
|
||||
{
|
||||
MediaPlayerService.jukeboxService.stopJukeboxService();
|
||||
jukeboxService.getValue().stopJukeboxService();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustJukeboxVolume(boolean up)
|
||||
{
|
||||
MediaPlayerService.jukeboxService.adjustVolume(up);
|
||||
jukeboxService.getValue().adjustVolume(up);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -756,9 +800,9 @@ public class DownloadServiceImpl implements DownloadService
|
||||
DownloadFile movedSong = list.remove(from);
|
||||
list.add(to, movedSong);
|
||||
|
||||
if (jukeboxEnabled && mainList)
|
||||
if (jukeboxService.getValue().isEnabled() && mainList)
|
||||
{
|
||||
MediaPlayerService.updateJukeboxPlaylist();
|
||||
jukeboxService.getValue().updatePlaylist();
|
||||
}
|
||||
else if (mainList && (movedSong == MediaPlayerService.nextPlaying || (currentPlayingIndex + 1) == to))
|
||||
{
|
||||
@ -797,11 +841,9 @@ public class DownloadServiceImpl implements DownloadService
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
final MusicService musicService = MusicServiceFactory.getMusicService(context);
|
||||
|
||||
try
|
||||
{
|
||||
musicService.setRating(song.getId(), rating, context, null);
|
||||
MusicServiceFactory.getMusicService(context).setRating(song.getId(), rating, context, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -812,9 +854,4 @@ public class DownloadServiceImpl implements DownloadService
|
||||
|
||||
updateNotification();
|
||||
}
|
||||
|
||||
private void handleError(Exception x)
|
||||
{
|
||||
Log.w(TAG, String.format("Media player error: %s", x), x);
|
||||
}
|
||||
}
|
@ -25,168 +25,80 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.media.AudioManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory;
|
||||
import org.moire.ultrasonic.domain.PlayerState;
|
||||
import org.moire.ultrasonic.util.CacheCleaner;
|
||||
import org.moire.ultrasonic.util.FileUtil;
|
||||
import org.moire.ultrasonic.util.Constants;
|
||||
import org.moire.ultrasonic.util.Util;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import kotlin.Lazy;
|
||||
|
||||
import static org.koin.java.standalone.KoinJavaComponent.inject;
|
||||
|
||||
/**
|
||||
* @author Sindre Mehus
|
||||
*/
|
||||
public class DownloadServiceLifecycleSupport
|
||||
{
|
||||
|
||||
private static final String TAG = DownloadServiceLifecycleSupport.class.getSimpleName();
|
||||
private static final String FILENAME_DOWNLOADS_SER = "downloadstate.ser";
|
||||
|
||||
private final DownloadServiceImpl downloadService;
|
||||
private ScheduledExecutorService executorService;
|
||||
private Lazy<DownloadQueueSerializer> downloadQueueSerializer = inject(DownloadQueueSerializer.class);
|
||||
private final DownloadServiceImpl downloadService; // From DI
|
||||
|
||||
private BroadcastReceiver headsetEventReceiver;
|
||||
private BroadcastReceiver ejectEventReceiver;
|
||||
private PhoneStateListener phoneStateListener;
|
||||
private boolean externalStorageAvailable = true;
|
||||
private Lock lock = new ReentrantLock();
|
||||
private final AtomicBoolean setup = new AtomicBoolean(false);
|
||||
private Context context;
|
||||
|
||||
/**
|
||||
* This receiver manages the intent that could come from other applications.
|
||||
*/
|
||||
private BroadcastReceiver intentReceiver = new BroadcastReceiver()
|
||||
{
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
String action = intent.getAction();
|
||||
Log.i(TAG, "intentReceiver.onReceive: " + action);
|
||||
if (DownloadServiceImpl.CMD_PLAY.equals(action))
|
||||
{
|
||||
downloadService.play();
|
||||
}
|
||||
else if (DownloadServiceImpl.CMD_NEXT.equals(action))
|
||||
{
|
||||
downloadService.next();
|
||||
}
|
||||
else if (DownloadServiceImpl.CMD_PREVIOUS.equals(action))
|
||||
{
|
||||
downloadService.previous();
|
||||
}
|
||||
else if (DownloadServiceImpl.CMD_TOGGLEPAUSE.equals(action))
|
||||
{
|
||||
downloadService.togglePlayPause();
|
||||
}
|
||||
else if (DownloadServiceImpl.CMD_PAUSE.equals(action))
|
||||
{
|
||||
downloadService.pause();
|
||||
}
|
||||
else if (DownloadServiceImpl.CMD_STOP.equals(action))
|
||||
{
|
||||
downloadService.pause();
|
||||
downloadService.seekTo(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public DownloadServiceLifecycleSupport(Context context, DownloadServiceImpl downloadService)
|
||||
public DownloadServiceLifecycleSupport(Context context, final DownloadServiceImpl downloadService)
|
||||
{
|
||||
this.downloadService = downloadService;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void onCreate()
|
||||
{
|
||||
Runnable downloadChecker = new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
MediaPlayerService.checkDownloads(context);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
Log.e(TAG, "checkDownloads() failed.", x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
executorService = Executors.newSingleThreadScheduledExecutor();
|
||||
executorService.scheduleWithFixedDelay(downloadChecker, 5, 5, TimeUnit.SECONDS);
|
||||
|
||||
registerHeadsetReceiver();
|
||||
|
||||
// Stop when SD card is ejected.
|
||||
ejectEventReceiver = new BroadcastReceiver()
|
||||
{
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
externalStorageAvailable = Intent.ACTION_MEDIA_MOUNTED.equals(intent.getAction());
|
||||
if (!externalStorageAvailable)
|
||||
{
|
||||
Log.i(TAG, "External media is ejecting. Stopping playback.");
|
||||
downloadService.reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.i(TAG, "External media is available.");
|
||||
}
|
||||
}
|
||||
};
|
||||
IntentFilter ejectFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT);
|
||||
ejectFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
|
||||
ejectFilter.addDataScheme("file");
|
||||
context.registerReceiver(ejectEventReceiver, ejectFilter);
|
||||
registerHeadsetReceiver();
|
||||
|
||||
// React to media buttons.
|
||||
Util.registerMediaButtonEventReceiver(context);
|
||||
|
||||
// Pause temporarily on incoming phone calls.
|
||||
//phoneStateListener = new MyPhoneStateListener();
|
||||
//TelephonyManager telephonyManager = (TelephonyManager) downloadService.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
//telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
|
||||
|
||||
// Register the handler for outside intents.
|
||||
IntentFilter commandFilter = new IntentFilter();
|
||||
commandFilter.addAction(DownloadServiceImpl.CMD_PLAY);
|
||||
commandFilter.addAction(DownloadServiceImpl.CMD_TOGGLEPAUSE);
|
||||
commandFilter.addAction(DownloadServiceImpl.CMD_PAUSE);
|
||||
commandFilter.addAction(DownloadServiceImpl.CMD_STOP);
|
||||
commandFilter.addAction(DownloadServiceImpl.CMD_PREVIOUS);
|
||||
commandFilter.addAction(DownloadServiceImpl.CMD_NEXT);
|
||||
commandFilter.addAction(Constants.CMD_PLAY);
|
||||
commandFilter.addAction(Constants.CMD_TOGGLEPAUSE);
|
||||
commandFilter.addAction(Constants.CMD_PAUSE);
|
||||
commandFilter.addAction(Constants.CMD_STOP);
|
||||
commandFilter.addAction(Constants.CMD_PREVIOUS);
|
||||
commandFilter.addAction(Constants.CMD_NEXT);
|
||||
commandFilter.addAction(Constants.CMD_PROCESS_KEYCODE);
|
||||
context.registerReceiver(intentReceiver, commandFilter);
|
||||
|
||||
int instance = Util.getActiveServer(context);
|
||||
downloadService.setJukeboxEnabled(Util.getJukeboxEnabled(context, instance));
|
||||
downloadQueueSerializer.getValue().deserializeDownloadQueue(new Consumer<State>() {
|
||||
@Override
|
||||
public void accept(State state) {
|
||||
downloadService.restore(state.songs, state.currentPlayingIndex, state.currentPlayingPosition, false, false);
|
||||
|
||||
deserializeDownloadQueue();
|
||||
// Work-around: Serialize again, as the restore() method creates a serialization without current playing info.
|
||||
downloadQueueSerializer.getValue().serializeDownloadQueue(downloadService.getSongs(),
|
||||
downloadService.getCurrentPlayingIndex(), downloadService.getPlayerPosition());
|
||||
}
|
||||
});
|
||||
|
||||
new CacheCleaner(context, downloadService).clean();
|
||||
new CacheCleaner(context).clean();
|
||||
Log.i(TAG, "LifecycleSupport created");
|
||||
}
|
||||
|
||||
private void registerHeadsetReceiver() {
|
||||
public void onDestroy()
|
||||
{
|
||||
downloadService.clear(false);
|
||||
context.unregisterReceiver(headsetEventReceiver);
|
||||
context.unregisterReceiver(intentReceiver);
|
||||
downloadService.onDestroy();
|
||||
Log.i(TAG, "LifecycleSupport destroyed");
|
||||
}
|
||||
|
||||
private void registerHeadsetReceiver() {
|
||||
// Pause when headset is unplugged.
|
||||
final SharedPreferences sp = Util.getPreferences(context);
|
||||
final String spKey = context
|
||||
@ -223,8 +135,9 @@ public class DownloadServiceLifecycleSupport
|
||||
context.registerReceiver(headsetEventReceiver, headsetIntentFilter);
|
||||
}
|
||||
|
||||
public void onStart(Intent intent)
|
||||
public void receiveIntent(Intent intent)
|
||||
{
|
||||
Log.i(TAG, "Received intent");
|
||||
if (intent != null && intent.getExtras() != null)
|
||||
{
|
||||
KeyEvent event = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT);
|
||||
@ -235,66 +148,6 @@ public class DownloadServiceLifecycleSupport
|
||||
}
|
||||
}
|
||||
|
||||
public void onDestroy()
|
||||
{
|
||||
executorService.shutdown();
|
||||
serializeDownloadQueueNow();
|
||||
downloadService.clear(false);
|
||||
context.unregisterReceiver(ejectEventReceiver);
|
||||
context.unregisterReceiver(headsetEventReceiver);
|
||||
context.unregisterReceiver(intentReceiver);
|
||||
}
|
||||
|
||||
public boolean isExternalStorageAvailable()
|
||||
{
|
||||
return externalStorageAvailable;
|
||||
}
|
||||
|
||||
public void serializeDownloadQueue()
|
||||
{
|
||||
if (!setup.get())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
new SerializeTask().execute();
|
||||
}
|
||||
|
||||
public void serializeDownloadQueueNow()
|
||||
{
|
||||
Iterable<DownloadFile> songs = new ArrayList<DownloadFile>(downloadService.getSongs());
|
||||
State state = new State();
|
||||
for (DownloadFile downloadFile : songs)
|
||||
{
|
||||
state.songs.add(downloadFile.getSong());
|
||||
}
|
||||
state.currentPlayingIndex = downloadService.getCurrentPlayingIndex();
|
||||
state.currentPlayingPosition = downloadService.getPlayerPosition();
|
||||
|
||||
Log.i(TAG, String.format("Serialized currentPlayingIndex: %d, currentPlayingPosition: %d", state.currentPlayingIndex, state.currentPlayingPosition));
|
||||
FileUtil.serialize(context, state, FILENAME_DOWNLOADS_SER);
|
||||
}
|
||||
|
||||
private void deserializeDownloadQueue()
|
||||
{
|
||||
new DeserializeTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
private void deserializeDownloadQueueNow()
|
||||
{
|
||||
State state = FileUtil.deserialize(context, FILENAME_DOWNLOADS_SER);
|
||||
if (state == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "Deserialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition);
|
||||
// TODO: here the autoPlay = false creates problems when Ultrasonic is started by a Play MediaButton as the player won't start this way.
|
||||
downloadService.restore(state.songs, state.currentPlayingIndex, state.currentPlayingPosition, false, false);
|
||||
|
||||
// Work-around: Serialize again, as the restore() method creates a serialization without current playing info.
|
||||
serializeDownloadQueue();
|
||||
}
|
||||
|
||||
private void handleKeyEvent(KeyEvent event)
|
||||
{
|
||||
if (event.getAction() != KeyEvent.ACTION_DOWN || event.getRepeatCount() > 0)
|
||||
@ -321,11 +174,7 @@ public class DownloadServiceLifecycleSupport
|
||||
downloadService.stop();
|
||||
break;
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY:
|
||||
if (downloadService.getPlayerState() == PlayerState.IDLE)
|
||||
{
|
||||
downloadService.play();
|
||||
}
|
||||
else if (downloadService.getPlayerState() != PlayerState.STARTED)
|
||||
if (downloadService.getPlayerState() != PlayerState.STARTED)
|
||||
{
|
||||
downloadService.start();
|
||||
}
|
||||
@ -354,87 +203,39 @@ public class DownloadServiceLifecycleSupport
|
||||
}
|
||||
|
||||
/**
|
||||
* Logic taken from packages/apps/Music. Will pause when an incoming
|
||||
* call rings or if a call (incoming or outgoing) is connected.
|
||||
* This receiver manages the intent that could come from other applications.
|
||||
*/
|
||||
private class MyPhoneStateListener extends PhoneStateListener
|
||||
private BroadcastReceiver intentReceiver = new BroadcastReceiver()
|
||||
{
|
||||
private boolean resumeAfterCall;
|
||||
|
||||
@Override
|
||||
public void onCallStateChanged(int state, String incomingNumber)
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
switch (state)
|
||||
String action = intent.getAction();
|
||||
if (action == null) return;
|
||||
Log.i(TAG, "intentReceiver.onReceive: " + action);
|
||||
|
||||
switch(action)
|
||||
{
|
||||
case TelephonyManager.CALL_STATE_RINGING:
|
||||
case TelephonyManager.CALL_STATE_OFFHOOK:
|
||||
if (downloadService.getPlayerState() == PlayerState.STARTED && !downloadService.isJukeboxEnabled())
|
||||
{
|
||||
resumeAfterCall = true;
|
||||
downloadService.pause();
|
||||
}
|
||||
case Constants.CMD_PLAY:
|
||||
downloadService.play();
|
||||
break;
|
||||
case TelephonyManager.CALL_STATE_IDLE:
|
||||
if (resumeAfterCall)
|
||||
{
|
||||
resumeAfterCall = false;
|
||||
downloadService.start();
|
||||
}
|
||||
case Constants.CMD_NEXT:
|
||||
downloadService.next();
|
||||
break;
|
||||
default:
|
||||
case Constants.CMD_PREVIOUS:
|
||||
downloadService.previous();
|
||||
break;
|
||||
case Constants.CMD_TOGGLEPAUSE:
|
||||
downloadService.togglePlayPause();
|
||||
break;
|
||||
case Constants.CMD_STOP:
|
||||
downloadService.pause();
|
||||
downloadService.seekTo(0);
|
||||
break;
|
||||
case Constants.CMD_PROCESS_KEYCODE:
|
||||
receiveIntent(intent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class State implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = -6346438781062572270L;
|
||||
|
||||
private List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>();
|
||||
private int currentPlayingIndex;
|
||||
private int currentPlayingPosition;
|
||||
}
|
||||
|
||||
private class SerializeTask extends AsyncTask<Void, Void, Void>
|
||||
{
|
||||
@Override
|
||||
protected Void doInBackground(Void... params)
|
||||
{
|
||||
if (lock.tryLock())
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.currentThread().setName("SerializeTask");
|
||||
serializeDownloadQueueNow();
|
||||
}
|
||||
finally
|
||||
{
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class DeserializeTask extends AsyncTask<Void, Void, Void>
|
||||
{
|
||||
@Override
|
||||
protected Void doInBackground(Void... params)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.currentThread().setName("DeserializeTask");
|
||||
lock.lock();
|
||||
deserializeDownloadQueueNow();
|
||||
setup.set(true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package org.moire.ultrasonic.service;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.util.Log;
|
||||
|
||||
public class ExternalStorageMonitor
|
||||
{
|
||||
private static final String TAG = ExternalStorageMonitor.class.getSimpleName();
|
||||
|
||||
private Context context;
|
||||
private BroadcastReceiver ejectEventReceiver;
|
||||
private boolean externalStorageAvailable = true;
|
||||
|
||||
public ExternalStorageMonitor(Context context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void onCreate(final Runnable ejectedCallback)
|
||||
{
|
||||
// Stop when SD card is ejected.
|
||||
ejectEventReceiver = new BroadcastReceiver()
|
||||
{
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
externalStorageAvailable = Intent.ACTION_MEDIA_MOUNTED.equals(intent.getAction());
|
||||
if (!externalStorageAvailable)
|
||||
{
|
||||
Log.i(TAG, "External media is ejecting. Stopping playback.");
|
||||
ejectedCallback.run();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.i(TAG, "External media is available.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
IntentFilter ejectFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT);
|
||||
ejectFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
|
||||
ejectFilter.addDataScheme("file");
|
||||
context.registerReceiver(ejectEventReceiver, ejectFilter);
|
||||
}
|
||||
|
||||
public void onDestroy()
|
||||
{
|
||||
context.unregisterReceiver(ejectEventReceiver);
|
||||
}
|
||||
|
||||
public boolean isExternalStorageAvailable() { return externalStorageAvailable; }
|
||||
}
|
@ -44,6 +44,10 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import kotlin.Lazy;
|
||||
|
||||
import static org.koin.java.standalone.KoinJavaComponent.inject;
|
||||
|
||||
/**
|
||||
* Provides an asynchronous interface to the remote jukebox on the Subsonic server.
|
||||
*
|
||||
@ -52,13 +56,10 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
*/
|
||||
public class JukeboxService
|
||||
{
|
||||
|
||||
private static final String TAG = JukeboxService.class.getSimpleName();
|
||||
private static final long STATUS_UPDATE_INTERVAL_SECONDS = 5L;
|
||||
|
||||
private final Handler handler = new Handler();
|
||||
private final TaskQueue tasks = new TaskQueue();
|
||||
private final DownloadServiceImpl downloadService;
|
||||
private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
|
||||
private ScheduledFuture<?> statusUpdateFuture;
|
||||
private final AtomicLong timeOfLastUpdate = new AtomicLong();
|
||||
@ -67,18 +68,20 @@ public class JukeboxService
|
||||
private VolumeToast volumeToast;
|
||||
private AtomicBoolean running = new AtomicBoolean();
|
||||
private Thread serviceThread;
|
||||
private boolean enabled = false;
|
||||
private Context context;
|
||||
|
||||
private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class);
|
||||
|
||||
// TODO: Report warning if queue fills up.
|
||||
// TODO: Create shutdown method?
|
||||
// TODO: Disable repeat.
|
||||
// TODO: Persist RC state?
|
||||
// TODO: Minimize status updates.
|
||||
|
||||
public JukeboxService(Context context, DownloadServiceImpl downloadService)
|
||||
public JukeboxService(Context context)
|
||||
{
|
||||
this.context = context;
|
||||
this.downloadService = downloadService;
|
||||
}
|
||||
|
||||
public void startJukeboxService()
|
||||
@ -179,9 +182,9 @@ public class JukeboxService
|
||||
// Track change?
|
||||
Integer index = jukeboxStatus.getCurrentPlayingIndex();
|
||||
|
||||
if (index != null && index != -1 && index != downloadService.getCurrentPlayingIndex())
|
||||
if (index != null && index != -1 && index != downloadServiceImpl.getValue().getCurrentPlayingIndex())
|
||||
{
|
||||
downloadService.setCurrentPlaying(index);
|
||||
downloadServiceImpl.getValue().setCurrentPlaying(index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,7 +212,7 @@ public class JukeboxService
|
||||
{
|
||||
Log.w(TAG, x.toString());
|
||||
|
||||
handler.post(new Runnable()
|
||||
new Handler().post(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
@ -218,17 +221,19 @@ public class JukeboxService
|
||||
}
|
||||
});
|
||||
|
||||
downloadService.setJukeboxEnabled(false);
|
||||
downloadServiceImpl.getValue().setJukeboxEnabled(false);
|
||||
}
|
||||
|
||||
public void updatePlaylist()
|
||||
{
|
||||
if (!enabled) return;
|
||||
|
||||
tasks.remove(Skip.class);
|
||||
tasks.remove(Stop.class);
|
||||
tasks.remove(Start.class);
|
||||
|
||||
List<String> ids = new ArrayList<String>();
|
||||
for (DownloadFile file : downloadService.getDownloads())
|
||||
for (DownloadFile file : downloadServiceImpl.getValue().getDownloads())
|
||||
{
|
||||
ids.add(file.getSong().getId());
|
||||
}
|
||||
@ -250,7 +255,7 @@ public class JukeboxService
|
||||
}
|
||||
|
||||
tasks.add(new Skip(index, offsetSeconds));
|
||||
downloadService.setPlayerState(PlayerState.STARTED);
|
||||
downloadServiceImpl.getValue().setPlayerState(PlayerState.STARTED);
|
||||
}
|
||||
|
||||
public void stop()
|
||||
@ -320,8 +325,11 @@ public class JukeboxService
|
||||
}
|
||||
|
||||
stop();
|
||||
}
|
||||
|
||||
downloadService.setPlayerState(PlayerState.IDLE);
|
||||
public boolean isEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
private static class TaskQueue
|
||||
|
@ -32,6 +32,7 @@ import androidx.core.app.NotificationManagerCompat;
|
||||
import org.koin.java.standalone.KoinJavaComponent;
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.activity.DownloadActivity;
|
||||
import org.moire.ultrasonic.activity.MainActivity;
|
||||
import org.moire.ultrasonic.activity.SubsonicTabActivity;
|
||||
import org.moire.ultrasonic.audiofx.EqualizerController;
|
||||
import org.moire.ultrasonic.audiofx.VisualizerController;
|
||||
@ -58,7 +59,13 @@ import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import kotlin.Lazy;
|
||||
|
||||
import static org.koin.java.standalone.KoinJavaComponent.inject;
|
||||
import static org.moire.ultrasonic.domain.PlayerState.COMPLETED;
|
||||
import static org.moire.ultrasonic.domain.PlayerState.DOWNLOADING;
|
||||
import static org.moire.ultrasonic.domain.PlayerState.IDLE;
|
||||
@ -101,9 +108,11 @@ public class MediaPlayerService extends Service
|
||||
public static DownloadFile currentDownloading;
|
||||
public static DownloadFile nextPlaying;
|
||||
|
||||
public static boolean jukeboxEnabled;
|
||||
public static JukeboxService jukeboxService;
|
||||
public static DownloadServiceLifecycleSupport lifecycleSupport;
|
||||
public Lazy<JukeboxService> jukeboxService = inject(JukeboxService.class);
|
||||
private Lazy<DownloadQueueSerializer> downloadQueueSerializer = inject(DownloadQueueSerializer.class);
|
||||
private Lazy<ExternalStorageMonitor> externalStorageMonitor = inject(ExternalStorageMonitor.class);
|
||||
|
||||
private ScheduledExecutorService executorService;
|
||||
|
||||
public static int cachedPosition;
|
||||
private PositionCache positionCache;
|
||||
@ -233,6 +242,25 @@ public class MediaPlayerService extends Service
|
||||
}
|
||||
}).start();
|
||||
|
||||
Runnable downloadChecker = new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
MediaPlayerService.checkDownloads(MediaPlayerService.this);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
Log.e(TAG, "checkDownloads() failed.", x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
executorService = Executors.newSingleThreadScheduledExecutor();
|
||||
executorService.scheduleWithFixedDelay(downloadChecker, 5, 5, TimeUnit.SECONDS);
|
||||
|
||||
audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
|
||||
setUpRemoteControlClient();
|
||||
|
||||
@ -274,7 +302,8 @@ public class MediaPlayerService extends Service
|
||||
|
||||
// We should use a single notification builder, otherwise the notification may not be updated
|
||||
notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
|
||||
|
||||
// Update notification early. It is better to show an empty one temporarily than waiting too long and letting Android kill the app
|
||||
updateNotification();
|
||||
instance = this;
|
||||
|
||||
Log.i(TAG, "MediaPlayerService created");
|
||||
@ -284,7 +313,6 @@ public class MediaPlayerService extends Service
|
||||
public int onStartCommand(Intent intent, int flags, int startId)
|
||||
{
|
||||
super.onStartCommand(intent, flags, startId);
|
||||
lifecycleSupport.onStart(intent);
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@ -296,6 +324,8 @@ public class MediaPlayerService extends Service
|
||||
instance = null;
|
||||
|
||||
reset();
|
||||
executorService.shutdown();
|
||||
|
||||
try
|
||||
{
|
||||
mediaPlayer.release();
|
||||
@ -501,9 +531,9 @@ public class MediaPlayerService extends Service
|
||||
{
|
||||
try
|
||||
{
|
||||
if (jukeboxEnabled)
|
||||
if (jukeboxService.getValue().isEnabled())
|
||||
{
|
||||
jukeboxService.skip(getCurrentPlayingIndex(), position / 1000);
|
||||
jukeboxService.getValue().skip(getCurrentPlayingIndex(), position / 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -528,7 +558,7 @@ public class MediaPlayerService extends Service
|
||||
return 0;
|
||||
}
|
||||
|
||||
return jukeboxEnabled ? jukeboxService.getPositionSeconds() * 1000 : cachedPosition;
|
||||
return jukeboxService.getValue().isEnabled() ? jukeboxService.getValue().getPositionSeconds() * 1000 : cachedPosition;
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
@ -736,9 +766,9 @@ public class MediaPlayerService extends Service
|
||||
|
||||
if (start)
|
||||
{
|
||||
if (jukeboxEnabled)
|
||||
if (jukeboxService.getValue().isEnabled())
|
||||
{
|
||||
jukeboxService.skip(getCurrentPlayingIndex(), 0);
|
||||
jukeboxService.getValue().skip(getCurrentPlayingIndex(), 0);
|
||||
setPlayerState(STARTED);
|
||||
}
|
||||
else
|
||||
@ -756,7 +786,7 @@ public class MediaPlayerService extends Service
|
||||
{
|
||||
reset();
|
||||
setCurrentPlaying(null);
|
||||
lifecycleSupport.serializeDownloadQueue();
|
||||
downloadQueueSerializer.getValue().serializeDownloadQueue(downloadList, getCurrentPlayingIndex(), getPlayerPosition());
|
||||
}
|
||||
|
||||
public synchronized void reset()
|
||||
@ -802,9 +832,9 @@ public class MediaPlayerService extends Service
|
||||
{
|
||||
if (playerState == STARTED)
|
||||
{
|
||||
if (jukeboxEnabled)
|
||||
if (jukeboxService.getValue().isEnabled())
|
||||
{
|
||||
jukeboxService.stop();
|
||||
jukeboxService.getValue().stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -825,9 +855,9 @@ public class MediaPlayerService extends Service
|
||||
{
|
||||
if (playerState == STARTED)
|
||||
{
|
||||
if (jukeboxEnabled)
|
||||
if (jukeboxService.getValue().isEnabled())
|
||||
{
|
||||
jukeboxService.stop();
|
||||
jukeboxService.getValue().stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -846,9 +876,9 @@ public class MediaPlayerService extends Service
|
||||
{
|
||||
try
|
||||
{
|
||||
if (jukeboxEnabled)
|
||||
if (jukeboxService.getValue().isEnabled())
|
||||
{
|
||||
jukeboxService.start();
|
||||
jukeboxService.getValue().start();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -885,7 +915,7 @@ public class MediaPlayerService extends Service
|
||||
|
||||
if (playerState == PAUSED)
|
||||
{
|
||||
lifecycleSupport.serializeDownloadQueue();
|
||||
downloadQueueSerializer.getValue().serializeDownloadQueue(downloadList, getCurrentPlayingIndex(), getPlayerPosition());
|
||||
}
|
||||
|
||||
if (playerState == PlayerState.STARTED)
|
||||
@ -1080,7 +1110,7 @@ public class MediaPlayerService extends Service
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleSupport.serializeDownloadQueue();
|
||||
downloadQueueSerializer.getValue().serializeDownloadQueue(downloadList, getCurrentPlayingIndex(), getPlayerPosition());
|
||||
}
|
||||
});
|
||||
|
||||
@ -1274,6 +1304,8 @@ public class MediaPlayerService extends Service
|
||||
if (Util.getShouldClearPlaylist(this))
|
||||
{
|
||||
clear(true);
|
||||
jukeboxService.getValue().updatePlaylist();
|
||||
downloadQueueSerializer.getValue().serializeDownloadQueue(downloadList, getCurrentPlayingIndex(), getPlayerPosition());
|
||||
}
|
||||
|
||||
resetPlayback();
|
||||
@ -1294,6 +1326,8 @@ public class MediaPlayerService extends Service
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Serialization was originally here, removed for static. refactor this and but back
|
||||
// downloadQueueSerializer.getValue().serializeDownloadQueue(downloadList, getCurrentPlayingIndex(), getPlayerPosition());
|
||||
public static synchronized void clear(boolean serialize)
|
||||
{
|
||||
MediaPlayerService mediaPlayerService = getRunningInstance();
|
||||
@ -1309,19 +1343,14 @@ public class MediaPlayerService extends Service
|
||||
if (mediaPlayerService != null)
|
||||
{
|
||||
mediaPlayerService.setCurrentPlaying(null);
|
||||
updateJukeboxPlaylist();
|
||||
mediaPlayerService.setNextPlaying();
|
||||
}
|
||||
|
||||
if (serialize)
|
||||
{
|
||||
lifecycleSupport.serializeDownloadQueue();
|
||||
}
|
||||
}
|
||||
|
||||
protected static synchronized void checkDownloads(Context context)
|
||||
{
|
||||
if (!Util.isExternalStoragePresent() || !lifecycleSupport.isExternalStorageAvailable())
|
||||
// TODO: refactor inject
|
||||
if (!Util.isExternalStoragePresent() || !inject(ExternalStorageMonitor.class).getValue().isExternalStorageAvailable())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -1331,7 +1360,8 @@ public class MediaPlayerService extends Service
|
||||
checkShufflePlay(context);
|
||||
}
|
||||
|
||||
if (jukeboxEnabled || !Util.isNetworkConnected(context))
|
||||
// TODO: This inject is ugly, refactor
|
||||
if (inject(JukeboxService.class).getValue().isEnabled() || !Util.isNetworkConnected(context))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -1472,7 +1502,7 @@ public class MediaPlayerService extends Service
|
||||
|
||||
if (revisionBefore != revision)
|
||||
{
|
||||
getInstance(context).updateJukeboxPlaylist();
|
||||
getInstance(context).jukeboxService.getValue().updatePlaylist();
|
||||
}
|
||||
|
||||
if (wasEmpty && !MediaPlayerService.downloadList.isEmpty())
|
||||
@ -1481,14 +1511,6 @@ public class MediaPlayerService extends Service
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateJukeboxPlaylist()
|
||||
{
|
||||
if (jukeboxEnabled)
|
||||
{
|
||||
jukeboxService.updatePlaylist();
|
||||
}
|
||||
}
|
||||
|
||||
private static synchronized void cleanup(Context context)
|
||||
{
|
||||
Iterator<DownloadFile> iterator = cleanupCandidates.iterator();
|
||||
|
@ -584,12 +584,6 @@ public class OfflineMusicService extends RESTMusicService
|
||||
@Override
|
||||
public MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception
|
||||
{
|
||||
DownloadService downloadService = DownloadServiceImpl.getInstance();
|
||||
if (downloadService == null)
|
||||
{
|
||||
return new MusicDirectory();
|
||||
}
|
||||
|
||||
Reader reader = null;
|
||||
BufferedReader buffer = null;
|
||||
try
|
||||
|
@ -0,0 +1,16 @@
|
||||
package org.moire.ultrasonic.service;
|
||||
|
||||
import org.moire.ultrasonic.domain.MusicDirectory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class State implements Serializable
|
||||
{
|
||||
public static final long serialVersionUID = -6346438781062572270L;
|
||||
|
||||
public List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>();
|
||||
public int currentPlayingIndex;
|
||||
public int currentPlayingPosition;
|
||||
}
|
@ -8,6 +8,7 @@ import android.util.Log;
|
||||
import org.moire.ultrasonic.domain.Playlist;
|
||||
import org.moire.ultrasonic.service.DownloadFile;
|
||||
import org.moire.ultrasonic.service.DownloadService;
|
||||
import org.moire.ultrasonic.service.DownloadServiceImpl;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@ -19,6 +20,10 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import kotlin.Lazy;
|
||||
|
||||
import static org.koin.java.standalone.KoinJavaComponent.inject;
|
||||
|
||||
/**
|
||||
* @author Sindre Mehus
|
||||
* @version $Id$
|
||||
@ -30,12 +35,11 @@ public class CacheCleaner
|
||||
private static final long MIN_FREE_SPACE = 500 * 1024L * 1024L;
|
||||
|
||||
private final Context context;
|
||||
private final DownloadService downloadService;
|
||||
private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class);
|
||||
|
||||
public CacheCleaner(Context context, DownloadService downloadService)
|
||||
public CacheCleaner(Context context)
|
||||
{
|
||||
this.context = context;
|
||||
this.downloadService = downloadService;
|
||||
}
|
||||
|
||||
public void clean()
|
||||
@ -219,7 +223,7 @@ public class CacheCleaner
|
||||
{
|
||||
Set<File> filesToNotDelete = new HashSet<File>(5);
|
||||
|
||||
for (DownloadFile downloadFile : downloadService.getDownloads())
|
||||
for (DownloadFile downloadFile : downloadServiceImpl.getValue().getDownloads())
|
||||
{
|
||||
filesToNotDelete.add(downloadFile.getPartialFile());
|
||||
filesToNotDelete.add(downloadFile.getCompleteFile());
|
||||
@ -234,12 +238,6 @@ public class CacheCleaner
|
||||
@Override
|
||||
protected Void doInBackground(Void... params)
|
||||
{
|
||||
if (downloadService == null)
|
||||
{
|
||||
Log.e(TAG, "DownloadService not set. Aborting cache cleaning.");
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Thread.currentThread().setName("BackgroundCleanup");
|
||||
@ -268,12 +266,6 @@ public class CacheCleaner
|
||||
@Override
|
||||
protected Void doInBackground(Void... params)
|
||||
{
|
||||
if (downloadService == null)
|
||||
{
|
||||
Log.e(TAG, "DownloadService not set. Aborting cache cleaning.");
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Thread.currentThread().setName("BackgroundSpaceCleanup");
|
||||
|
@ -60,6 +60,15 @@ public final class Constants
|
||||
public static final String INTENT_EXTRA_NAME_IS_ALBUM = "subsonic.isalbum";
|
||||
public static final String INTENT_EXTRA_NAME_VIDEOS = "subsonic.videos";
|
||||
|
||||
// Names for Intent Actions
|
||||
public static final String CMD_PROCESS_KEYCODE = "org.moire.ultrasonic.CMD_PROCESS_KEYCODE";
|
||||
public static final String CMD_PLAY = "org.moire.ultrasonic.CMD_PLAY";
|
||||
public static final String CMD_TOGGLEPAUSE = "org.moire.ultrasonic.CMD_TOGGLEPAUSE";
|
||||
public static final String CMD_PAUSE = "org.moire.ultrasonic.CMD_PAUSE";
|
||||
public static final String CMD_STOP = "org.moire.ultrasonic.CMD_STOP";
|
||||
public static final String CMD_PREVIOUS = "org.moire.ultrasonic.CMD_PREVIOUS";
|
||||
public static final String CMD_NEXT = "org.moire.ultrasonic.CMD_NEXT";
|
||||
|
||||
// Notification IDs.
|
||||
public static final int NOTIFICATION_ID_PLAYING = 100;
|
||||
|
||||
@ -140,6 +149,8 @@ public final class Constants
|
||||
// URL for project donations.
|
||||
public static final String DONATION_URL = "http://www.subsonic.org/pages/premium.jsp";
|
||||
|
||||
public static final String FILENAME_DOWNLOADS_SER = "downloadstate.ser";
|
||||
|
||||
public static final String ALBUM_ART_FILE = "folder.jpeg";
|
||||
public static final String STARRED = "starred";
|
||||
public static final String ALPHABETICAL_BY_NAME = "alphabeticalByName";
|
||||
|
@ -56,6 +56,7 @@ import org.moire.ultrasonic.receiver.MediaButtonIntentReceiver;
|
||||
import org.moire.ultrasonic.service.DownloadFile;
|
||||
import org.moire.ultrasonic.service.DownloadService;
|
||||
import org.moire.ultrasonic.service.DownloadServiceImpl;
|
||||
import org.moire.ultrasonic.service.DownloadServiceLifecycleSupport;
|
||||
import org.moire.ultrasonic.service.MediaPlayerService;
|
||||
import org.moire.ultrasonic.service.MusicServiceFactory;
|
||||
|
||||
@ -1283,58 +1284,58 @@ public class Util extends DownloadActivity
|
||||
views.setOnClickPendingIntent(R.id.appwidget_top, pendingIntent);
|
||||
|
||||
// Emulate media button clicks.
|
||||
intent = new Intent("1");
|
||||
intent.setComponent(new ComponentName(context, MediaPlayerService.class));
|
||||
intent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
intent.setPackage(context.getPackageName());
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
pendingIntent = PendingIntent.getBroadcast(context, 1, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.control_play, pendingIntent);
|
||||
|
||||
intent = new Intent("2");
|
||||
intent.setComponent(new ComponentName(context, MediaPlayerService.class));
|
||||
intent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
intent.setPackage(context.getPackageName());
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
pendingIntent = PendingIntent.getBroadcast(context, 2, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.control_next, pendingIntent);
|
||||
|
||||
intent = new Intent("3");
|
||||
intent.setComponent(new ComponentName(context, MediaPlayerService.class));
|
||||
intent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
intent.setPackage(context.getPackageName());
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PREVIOUS));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
pendingIntent = PendingIntent.getBroadcast(context, 3, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.control_previous, pendingIntent);
|
||||
|
||||
intent = new Intent("4");
|
||||
intent.setComponent(new ComponentName(context, MediaPlayerService.class));
|
||||
intent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
intent.setPackage(context.getPackageName());
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_STOP));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
pendingIntent = PendingIntent.getBroadcast(context, 4, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.control_stop, pendingIntent);
|
||||
|
||||
intent = new Intent("RATE_1");
|
||||
intent.setComponent(new ComponentName(context, MediaPlayerService.class));
|
||||
intent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
intent.setPackage(context.getPackageName());
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_1));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
pendingIntent = PendingIntent.getBroadcast(context, 5, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.notification_five_star_1, pendingIntent);
|
||||
|
||||
intent = new Intent("RATE_2");
|
||||
intent.setComponent(new ComponentName(context, MediaPlayerService.class));
|
||||
intent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
intent.setPackage(context.getPackageName());
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_2));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
pendingIntent = PendingIntent.getBroadcast(context, 6, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.notification_five_star_2, pendingIntent);
|
||||
|
||||
intent = new Intent("RATE_3");
|
||||
intent.setComponent(new ComponentName(context, MediaPlayerService.class));
|
||||
intent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
intent.setPackage(context.getPackageName());
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_3));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
pendingIntent = PendingIntent.getBroadcast(context, 7, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.notification_five_star_3, pendingIntent);
|
||||
|
||||
intent = new Intent("RATE_4");
|
||||
intent.setComponent(new ComponentName(context, MediaPlayerService.class));
|
||||
intent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
intent.setPackage(context.getPackageName());
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_4));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
pendingIntent = PendingIntent.getBroadcast(context, 8, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.notification_five_star_4, pendingIntent);
|
||||
|
||||
intent = new Intent("RATE_5");
|
||||
intent.setComponent(new ComponentName(context, MediaPlayerService.class));
|
||||
intent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
intent.setPackage(context.getPackageName());
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_5));
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
pendingIntent = PendingIntent.getBroadcast(context, 9, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.notification_five_star_5, pendingIntent);
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,10 @@ import org.moire.ultrasonic.util.VideoPlayerType;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import kotlin.Lazy;
|
||||
|
||||
import static org.koin.java.standalone.KoinJavaComponent.inject;
|
||||
|
||||
/**
|
||||
* Used to display songs in a {@code ListView}.
|
||||
*
|
||||
@ -72,13 +76,14 @@ public class SongView extends UpdateView implements Checkable
|
||||
private ImageType leftImageType;
|
||||
private ImageType rightImageType;
|
||||
private Drawable rightImage;
|
||||
private DownloadService downloadService;
|
||||
private DownloadFile downloadFile;
|
||||
private boolean playing;
|
||||
private EntryAdapter.SongViewHolder viewHolder;
|
||||
private boolean maximized = false;
|
||||
private boolean useFiveStarRating;
|
||||
|
||||
private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class);
|
||||
|
||||
public SongView(Context context)
|
||||
{
|
||||
super(context);
|
||||
@ -164,10 +169,7 @@ public class SongView extends UpdateView implements Checkable
|
||||
|
||||
this.song = song;
|
||||
|
||||
if (downloadService != null)
|
||||
{
|
||||
this.downloadFile = downloadService.forSong(song);
|
||||
}
|
||||
this.downloadFile = downloadServiceImpl.getValue().forSong(song);
|
||||
|
||||
StringBuilder artist = new StringBuilder(60);
|
||||
|
||||
@ -311,10 +313,6 @@ public class SongView extends UpdateView implements Checkable
|
||||
@Override
|
||||
protected void updateBackground()
|
||||
{
|
||||
if (downloadService == null)
|
||||
{
|
||||
downloadService = DownloadServiceImpl.getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -322,12 +320,7 @@ public class SongView extends UpdateView implements Checkable
|
||||
{
|
||||
updateBackground();
|
||||
|
||||
if (downloadService == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
downloadFile = downloadService.forSong(this.song);
|
||||
downloadFile = downloadServiceImpl.getValue().forSong(this.song);
|
||||
File partialFile = downloadFile.getPartialFile();
|
||||
|
||||
if (downloadFile.isWorkDone())
|
||||
@ -417,7 +410,7 @@ public class SongView extends UpdateView implements Checkable
|
||||
viewHolder.fiveStar4.setImageDrawable(rating > 3 ? starDrawable : starHollowDrawable);
|
||||
viewHolder.fiveStar5.setImageDrawable(rating > 4 ? starDrawable : starHollowDrawable);
|
||||
|
||||
boolean playing = downloadService.getCurrentPlaying() == downloadFile;
|
||||
boolean playing = downloadServiceImpl.getValue().getCurrentPlaying() == downloadFile;
|
||||
|
||||
if (playing)
|
||||
{
|
||||
|
@ -30,6 +30,10 @@ import org.moire.ultrasonic.domain.PlayerState;
|
||||
import org.moire.ultrasonic.service.DownloadService;
|
||||
import org.moire.ultrasonic.service.DownloadServiceImpl;
|
||||
|
||||
import kotlin.Lazy;
|
||||
|
||||
import static org.koin.java.standalone.KoinJavaComponent.inject;
|
||||
|
||||
/**
|
||||
* A simple class that draws waveform data received from a
|
||||
* {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture}
|
||||
@ -39,7 +43,6 @@ import org.moire.ultrasonic.service.DownloadServiceImpl;
|
||||
*/
|
||||
public class VisualizerView extends View
|
||||
{
|
||||
|
||||
private static final int PREFERRED_CAPTURE_RATE_MILLIHERTZ = 20000;
|
||||
|
||||
private final Paint paint = new Paint();
|
||||
@ -48,6 +51,8 @@ public class VisualizerView extends View
|
||||
private float[] points;
|
||||
private boolean active;
|
||||
|
||||
private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class);
|
||||
|
||||
public VisualizerView(Context context)
|
||||
{
|
||||
super(context);
|
||||
@ -97,10 +102,9 @@ public class VisualizerView extends View
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private static Visualizer getVizualizer()
|
||||
private Visualizer getVizualizer()
|
||||
{
|
||||
DownloadService downloadService = DownloadServiceImpl.getInstance();
|
||||
VisualizerController visualizerController = downloadService == null ? null : downloadService.getVisualizerController();
|
||||
VisualizerController visualizerController = downloadServiceImpl.getValue().getVisualizerController();
|
||||
return visualizerController == null ? null : visualizerController.getVisualizer();
|
||||
}
|
||||
|
||||
@ -120,8 +124,7 @@ public class VisualizerView extends View
|
||||
return;
|
||||
}
|
||||
|
||||
DownloadService downloadService = DownloadServiceImpl.getInstance();
|
||||
if (downloadService != null && downloadService.getPlayerState() != PlayerState.STARTED)
|
||||
if (downloadServiceImpl.getValue().getPlayerState() != PlayerState.STARTED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package org.moire.ultrasonic.di
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Log
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
import kotlin.math.abs
|
||||
import org.koin.dsl.module.module
|
||||
import org.moire.ultrasonic.BuildConfig
|
||||
@ -11,10 +12,7 @@ import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicClientConfiguration
|
||||
import org.moire.ultrasonic.api.subsonic.di.subsonicApiModule
|
||||
import org.moire.ultrasonic.cache.PermanentFileStorage
|
||||
import org.moire.ultrasonic.service.CachedMusicService
|
||||
import org.moire.ultrasonic.service.MusicService
|
||||
import org.moire.ultrasonic.service.OfflineMusicService
|
||||
import org.moire.ultrasonic.service.RESTMusicService
|
||||
import org.moire.ultrasonic.service.*
|
||||
import org.moire.ultrasonic.subsonic.loader.image.SubsonicImageLoader
|
||||
import org.moire.ultrasonic.util.Constants
|
||||
|
||||
@ -113,4 +111,10 @@ val musicServiceModule = module(MUSIC_SERVICE_CONTEXT) {
|
||||
}
|
||||
|
||||
single { SubsonicImageLoader(getProperty(DiProperties.APP_CONTEXT), get()) }
|
||||
|
||||
single { DownloadServiceImpl(androidContext()) }
|
||||
single { JukeboxService(androidContext()) }
|
||||
single { DownloadServiceLifecycleSupport(androidContext(), get())}
|
||||
single { DownloadQueueSerializer(androidContext())}
|
||||
single { ExternalStorageMonitor(androidContext())}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user