From 2c8229b0dcdfed94d16c41f94bec25c66f805d60 Mon Sep 17 00:00:00 2001 From: dkanada Date: Sat, 17 Oct 2020 17:07:36 +0900 Subject: [PATCH] add getVolume to playback interface and improve progress handler --- .../gramophone/service/MultiPlayer.java | 21 ++--- .../gramophone/service/MusicService.java | 85 ++++++++++--------- .../gramophone/service/playback/Playback.java | 6 +- .../ui/activities/SplashActivity.java | 7 +- 4 files changed, 61 insertions(+), 58 deletions(-) diff --git a/app/src/main/java/com/dkanada/gramophone/service/MultiPlayer.java b/app/src/main/java/com/dkanada/gramophone/service/MultiPlayer.java index 7603f4f7..4c9434f2 100644 --- a/app/src/main/java/com/dkanada/gramophone/service/MultiPlayer.java +++ b/app/src/main/java/com/dkanada/gramophone/service/MultiPlayer.java @@ -2,10 +2,10 @@ package com.dkanada.gramophone.service; import android.content.Context; import android.net.Uri; -import android.os.Environment; import android.util.Log; import android.widget.Toast; +import com.dkanada.gramophone.App; import com.dkanada.gramophone.R; import com.dkanada.gramophone.model.Song; import com.dkanada.gramophone.service.playback.Playback; @@ -118,7 +118,8 @@ public class MultiPlayer implements Playback { LeastRecentlyUsedCacheEvictor recentlyUsedCache = new LeastRecentlyUsedCacheEvictor(Long.MAX_VALUE); ExoDatabaseProvider databaseProvider = new ExoDatabaseProvider(context); - simpleCache = new SimpleCache(new File(Environment.getExternalStorageDirectory() + "/Gelli/cache"), recentlyUsedCache, databaseProvider); + File file = new File(App.getInstance().getApplicationInfo().dataDir + "/Gelli/exoplayer"); + simpleCache = new SimpleCache(file, recentlyUsedCache, databaseProvider); dataSource = buildDataSourceFactory(); } @@ -184,12 +185,7 @@ public class MultiPlayer implements Playback { .createMediaSource(uri); } - if (mediaSource.getSize() < position) { - mediaSource.addMediaSource(mediaSource.getSize(), source); - } else { - mediaSource.addMediaSource(position, source); - } - + mediaSource.addMediaSource(Math.min(mediaSource.getSize(), position), source); if (position == 0) start(); } }); @@ -247,7 +243,7 @@ public class MultiPlayer implements Playback { } @Override - public int getPosition() { + public int getProgress() { if (!isReady) return -1; return (int) exoPlayer.getCurrentPosition(); } @@ -259,7 +255,7 @@ public class MultiPlayer implements Playback { } @Override - public void setPosition(int position) { + public void setProgress(int position) { exoPlayer.seekTo(position); } @@ -267,4 +263,9 @@ public class MultiPlayer implements Playback { public void setVolume(int volume) { exoPlayer.setVolume(volume / 100f); } + + @Override + public int getVolume() { + return (int) (exoPlayer.getVolume() * 100); + } } diff --git a/app/src/main/java/com/dkanada/gramophone/service/MusicService.java b/app/src/main/java/com/dkanada/gramophone/service/MusicService.java index a93ab021..e6e5bf34 100644 --- a/app/src/main/java/com/dkanada/gramophone/service/MusicService.java +++ b/app/src/main/java/com/dkanada/gramophone/service/MusicService.java @@ -63,8 +63,10 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Random; -import java.util.Timer; -import java.util.TimerTask; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; public class MusicService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener, Playback.PlaybackCallbacks { public static final String PHONOGRAPH_PACKAGE_NAME = "com.dkanada.gramophone"; @@ -78,7 +80,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP public static final String ACTION_REWIND = PHONOGRAPH_PACKAGE_NAME + ".rewind"; public static final String ACTION_QUIT = PHONOGRAPH_PACKAGE_NAME + ".quitservice"; public static final String ACTION_PENDING_QUIT = PHONOGRAPH_PACKAGE_NAME + ".pendingquitservice"; - public static final String INTENT_EXTRA_PLAYLIST = PHONOGRAPH_PACKAGE_NAME + "intentextra.playlist"; + public static final String INTENT_EXTRA_PLAYLIST = PHONOGRAPH_PACKAGE_NAME + ".intentextra.playlist"; public static final String INTENT_EXTRA_SHUFFLE_MODE = PHONOGRAPH_PACKAGE_NAME + ".intentextra.shufflemode"; public static final String APP_WIDGET_UPDATE = PHONOGRAPH_PACKAGE_NAME + ".appwidgetupdate"; @@ -101,7 +103,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP public static final int FOCUS_CHANGE = 6; public static final int DUCK = 7; public static final int UNDUCK = 8; - public static final int RESTORE_QUEUES = 9; public static final int SHUFFLE_MODE_NONE = 0; public static final int SHUFFLE_MODE_SHUFFLE = 1; @@ -111,6 +112,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP public static final int REPEAT_MODE_THIS = 2; public static final int SAVE_QUEUE = 0; + public static final int LOAD_QUEUE = 9; private final IBinder musicBinder = new MusicBinder(); @@ -121,10 +123,13 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP private AppWidgetClassic appWidgetClassic = AppWidgetClassic.getInstance(); private Playback playback; + private List playingQueue = new ArrayList<>(); private List originalPlayingQueue = new ArrayList<>(); + private int position = -1; private int nextPosition = -1; + private int shuffleMode; private int repeatMode; private boolean queuesRestored; @@ -146,6 +151,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP private ThrottledSeekHandler throttledSeekHandler; private QueueSaveHandler queueSaveHandler; private ProgressHandler progressHandler; + private HandlerThread playerHandlerThread; private HandlerThread queueSaveHandlerThread; @@ -176,16 +182,13 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName()); wakeLock.setReferenceCounted(false); + playback = new MultiPlayer(this); + playback.setCallbacks(this); + playerHandlerThread = new HandlerThread(PlaybackHandler.class.getName()); playerHandlerThread.start(); playerHandler = new PlaybackHandler(this, playerHandlerThread.getLooper()); - playback = new MultiPlayer(this); - playback.setCallbacks(this); - - initMediaSession(); - - // queue saving needs to run on a separate thread so that it doesn't block the playback handler events queueSaveHandlerThread = new HandlerThread(QueueSaveHandler.class.getName(), Process.THREAD_PRIORITY_BACKGROUND); queueSaveHandlerThread.start(); queueSaveHandler = new QueueSaveHandler(this, queueSaveHandlerThread.getLooper()); @@ -200,6 +203,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP PreferenceUtil.getInstance(this).registerOnSharedPreferenceChangedListener(this); initNotification(); + initMediaSession(); restoreState(); mediaSession.setActive(true); @@ -388,8 +392,8 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP notifyChange(SHUFFLE_MODE_CHANGED); notifyChange(REPEAT_MODE_CHANGED); - playerHandler.removeMessages(RESTORE_QUEUES); - playerHandler.sendEmptyMessage(RESTORE_QUEUES); + playerHandler.removeMessages(LOAD_QUEUE); + playerHandler.sendEmptyMessage(LOAD_QUEUE); } private synchronized void restoreQueuesAndPositionIfNecessary() { @@ -843,7 +847,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP } public int getSongProgressMillis() { - return playback.getPosition(); + return playback.getProgress(); } public int getSongDurationMillis() { @@ -861,7 +865,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP public int seek(int millis) { synchronized (this) { - playback.setPosition(millis); + playback.setProgress(millis); throttledSeekHandler.notifySeek(); return millis; } @@ -1112,7 +1116,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP service.prepareNextImpl(); break; - case RESTORE_QUEUES: + case LOAD_QUEUE: service.restoreQueuesAndPositionIfNecessary(); break; @@ -1196,33 +1200,29 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP @Override public void run() { - saveProgress(); notifyChange(PLAY_STATE_CHANGED); } } private static final class ProgressHandler extends Handler { private WeakReference mService; - private Timer mTimer; + + private ScheduledExecutorService executorService; + private Future task; public ProgressHandler(MusicService service, Looper looper) { super(looper); mService = new WeakReference<>(service); - mTimer = new Timer(); } @Override public void handleMessage(@NonNull final Message msg) { - final MusicService service = mService.get(); - if (service == null) { - return; - } - switch (msg.what) { case PLAY_SONG: - case TRACK_WENT_TO_NEXT: onStart(); + case TRACK_WENT_TO_NEXT: + onNext(); break; case TRACK_ENDED: onStop(); @@ -1230,20 +1230,21 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP } public void onStart() { + if (executorService != null) executorService.shutdownNow(); + + executorService = Executors.newScheduledThreadPool(1); + task = executorService.scheduleAtFixedRate(this::onProgress, 10, 10, TimeUnit.SECONDS); + } + + public void onNext() { PlaybackStartInfo startInfo = new PlaybackStartInfo(); - TimerTask mTask = new TimerTask() { - @Override - public void run() { - onProgress(); - } - }; startInfo.setItemId(mService.get().getCurrentSong().id); + startInfo.setVolumeLevel(mService.get().playback.getVolume()); startInfo.setCanSeek(true); startInfo.setIsPaused(false); App.getApiClient().ReportPlaybackStartAsync(startInfo, new EmptyResponse()); - mTimer.schedule(mTask, 10000, 10000); } public void onProgress() { @@ -1252,26 +1253,26 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP // TODO these cause a wrong thread error long progress = mService.get().getSongProgressMillis(); double duration = mService.get().getSongDurationMillis(); - if (progress / duration > 0.9) onStop(); + if (progress / duration > 0.9) { + Song current = mService.get().getCurrentSong(); + String user = App.getApiClient().getCurrentUserId(); + Date time = new Date(System.currentTimeMillis()); + + App.getApiClient().MarkPlayedAsync(current.id, user, time, new Response<>()); + } progressInfo.setItemId(mService.get().getCurrentSong().id); progressInfo.setPositionTicks(progress * 10000); - progressInfo.setCanSeek(true); + progressInfo.setVolumeLevel(mService.get().playback.getVolume()); progressInfo.setIsPaused(!mService.get().playback.isPlaying()); + progressInfo.setCanSeek(true); - App.getApiClient().ensureWebSocket(); App.getApiClient().ReportPlaybackProgressAsync(progressInfo, new EmptyResponse()); } public void onStop() { - mTimer.purge(); - - Song current = mService.get().getCurrentSong(); - String user = App.getApiClient().getCurrentUserId(); - Date time = new Date(System.currentTimeMillis()); - - if (current == Song.EMPTY_SONG) return; - App.getApiClient().MarkPlayedAsync(current.id, user, time, new Response<>()); + task.cancel(true); + executorService.shutdownNow(); } } } diff --git a/app/src/main/java/com/dkanada/gramophone/service/playback/Playback.java b/app/src/main/java/com/dkanada/gramophone/service/playback/Playback.java index 1c477cd2..9b643360 100644 --- a/app/src/main/java/com/dkanada/gramophone/service/playback/Playback.java +++ b/app/src/main/java/com/dkanada/gramophone/service/playback/Playback.java @@ -19,14 +19,16 @@ public interface Playback { boolean isPlaying(); - int getPosition(); + int getProgress(); int getDuration(); - void setPosition(int position); + void setProgress(int position); void setVolume(int volume); + int getVolume(); + interface PlaybackCallbacks { void onTrackStarted(); diff --git a/app/src/main/java/com/dkanada/gramophone/ui/activities/SplashActivity.java b/app/src/main/java/com/dkanada/gramophone/ui/activities/SplashActivity.java index 713bce16..ea19a38b 100644 --- a/app/src/main/java/com/dkanada/gramophone/ui/activities/SplashActivity.java +++ b/app/src/main/java/com/dkanada/gramophone/ui/activities/SplashActivity.java @@ -55,16 +55,16 @@ public class SplashActivity extends AbsBaseActivity { builder.setMessage(R.string.battery_optimizations_message) .setTitle(R.string.battery_optimizations_title) .setNegativeButton(R.string.ignore, (dialog, id) -> login()) - .setPositiveButton(R.string.disable, (dialog, id) -> openPowerSettings(SplashActivity.this)) + .setPositiveButton(R.string.disable, (dialog, id) -> openPowerSettings()) .show(); } @RequiresApi(api = Build.VERSION_CODES.M) - private void openPowerSettings(Context context) { + private void openPowerSettings() { Intent intent = new Intent(); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS); - context.startActivity(intent); + startActivity(intent); } public void login() { @@ -102,6 +102,5 @@ public class SplashActivity extends AbsBaseActivity { Intent intent = new Intent(this, LoginActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); startActivity(intent); - finish(); } }