Rx Java and Normal compatible for all query

This commit is contained in:
h4h13 2019-08-02 14:29:40 +05:30
parent 850036e5cc
commit c2759e3ec0
89 changed files with 2900 additions and 1040 deletions

View file

@ -27,12 +27,7 @@ import android.util.Log
import android.view.KeyEvent
import androidx.core.content.ContextCompat
import code.name.monkey.retromusic.BuildConfig
import code.name.monkey.retromusic.Constants.ACTION_PAUSE
import code.name.monkey.retromusic.Constants.ACTION_PLAY
import code.name.monkey.retromusic.Constants.ACTION_REWIND
import code.name.monkey.retromusic.Constants.ACTION_SKIP
import code.name.monkey.retromusic.Constants.ACTION_STOP
import code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE
import code.name.monkey.retromusic.service.MusicService.*
/**

View file

@ -0,0 +1,155 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.service
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.support.v4.media.session.MediaSessionCompat
import code.name.monkey.retromusic.auto.AutoMediaIDHelper
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.ShuffleHelper
import code.name.monkey.retromusic.loaders.*
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.providers.MusicPlaybackQueueStore
import code.name.monkey.retromusic.service.MusicService.TOGGLE_FAVORITE
import code.name.monkey.retromusic.util.MusicUtil
import java.util.*
/**
* Created by hemanths on 2019-08-01.
*/
class MediaSessionCallback(private val context: Context,
private val musicService: MusicService) : MediaSessionCompat.Callback() {
override fun onPlay() {
super.onPlay()
musicService.play()
}
override fun onPause() {
super.onPause()
musicService.pause()
}
override fun onSkipToNext() {
super.onSkipToNext()
musicService.playNextSong(true)
}
override fun onSkipToPrevious() {
super.onSkipToPrevious()
musicService.back(true)
}
override fun onStop() {
super.onStop()
musicService.quit()
}
override fun onSeekTo(pos: Long) {
super.onSeekTo(pos)
musicService.seek(pos.toInt())
}
override fun onMediaButtonEvent(mediaButtonIntent: Intent): Boolean {
return MediaButtonIntentReceiver.handleIntent(context, mediaButtonIntent)
}
override fun onPlayFromMediaId(mediaId: String?, extras: Bundle?) {
super.onPlayFromMediaId(mediaId, extras)
val musicId = mediaId?.let { AutoMediaIDHelper.extractMusicID(it) }
val itemId = musicId?.toInt() ?: -1
val songs = arrayListOf<Song>()
when (val category = mediaId?.let { AutoMediaIDHelper.extractCategory(it) }) {
AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM -> {
val album = AlbumLoader.getAlbum(context, itemId)
album.songs?.let { songs.addAll(it) }
openQueue(songs, 0, true)
}
AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST -> {
val artist = ArtistLoader.getArtist(context, itemId)
songs.addAll(artist.songs)
openQueue(songs, 0, true)
}
AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_PLAYLIST -> {
val playlist = PlaylistLoader.getPlaylist(context, itemId)
songs.addAll(playlist.getSongs(context))
openQueue(songs, 0, true)
}
AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_HISTORY,
AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_TOP_TRACKS,
AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_QUEUE -> {
val tracks: List<Song>
if (category.equals(AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_HISTORY)) {
tracks = TopAndRecentlyPlayedTracksLoader.getRecentlyPlayedTracks(context)
} else if (category.equals(AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_TOP_TRACKS)) {
tracks = TopAndRecentlyPlayedTracksLoader.getTopTracks(context)
} else {
tracks = MusicPlaybackQueueStore.getInstance(context).savedOriginalPlayingQueue
}
songs.addAll(tracks)
var songIndex = MusicUtil.indexOfSongInList(tracks, itemId)
if (songIndex == -1) {
songIndex = 0
}
openQueue(songs, songIndex, true)
}
AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_SHUFFLE -> {
val allSongs = SongLoader.getAllSongs(context)
ShuffleHelper.makeShuffleList(allSongs, -1)
openQueue(allSongs, 0, true)
}
}
}
override fun onCustomAction(action: String, extras: Bundle?) {
when (action) {
/* CYCLE_REPEAT -> {
cycleRepeatMode()
musicService.updateMediaSessionPlaybackState()
}
TOGGLE_SHUFFLE -> {
musicService.toggleShuffle()
musicService.updateMediaSessionPlaybackState()
}
*/
TOGGLE_FAVORITE -> {
MusicUtil.toggleFavorite(context, MusicPlayerRemote.currentSong)
musicService.updateMediaSessionPlaybackState()
}
else -> {
println("Unsupported action: $action")
}
}
}
private fun checkAndStartPlaying(songs: ArrayList<Song>, itemId: Int) {
var songIndex = MusicUtil.indexOfSongInList(songs, itemId)
if (songIndex == -1) {
songIndex = 0
}
openQueue(songs, songIndex)
}
private fun openQueue(songs: ArrayList<Song>, index: Int, startPlaying: Boolean = true) {
MusicPlayerRemote.openQueue(songs, index, startPlaying)
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.service;
import android.database.ContentObserver;
import android.os.Handler;
public class MediaStoreObserver extends ContentObserver implements Runnable {
// milliseconds to delay before calling refresh to aggregate events
private static final long REFRESH_DELAY = 500;
private final MusicService musicService;
private Handler mHandler;
MediaStoreObserver(MusicService musicService, Handler handler) {
super(handler);
this.musicService = musicService;
mHandler = handler;
}
@Override
public void onChange(boolean selfChange) {
// if a change is detected, remove any scheduled callback
// then post a new one. This is intended to prevent closely
// spaced events from generating multiple refresh calls
mHandler.removeCallbacks(this);
mHandler.postDelayed(this, REFRESH_DELAY);
}
@Override
public void run() {
// actually call refresh when the delayed callback fires
// do not send a sticky broadcast here
musicService.handleAndSendChangeInternal(MusicService.MEDIA_STORE_CHANGED);
}
}

View file

@ -15,7 +15,6 @@
package code.name.monkey.retromusic.service;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@ -31,15 +30,15 @@ import android.media.AudioManager;
import android.media.audiofx.AudioEffect;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.support.v4.media.MediaBrowserCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
@ -50,10 +49,10 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.media.MediaBrowserServiceCompat;
import com.bumptech.glide.request.transition.Transition;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@ -64,15 +63,14 @@ import code.name.monkey.retromusic.appwidgets.AppWidgetCard;
import code.name.monkey.retromusic.appwidgets.AppWidgetClassic;
import code.name.monkey.retromusic.appwidgets.AppWidgetSmall;
import code.name.monkey.retromusic.appwidgets.AppWidgetText;
import code.name.monkey.retromusic.auto.AutoMediaIDHelper;
import code.name.monkey.retromusic.auto.AutoMusicProvider;
import code.name.monkey.retromusic.glide.BlurTransformation;
import code.name.monkey.retromusic.glide.GlideApp;
import code.name.monkey.retromusic.glide.GlideRequest;
import code.name.monkey.retromusic.glide.RetroGlideExtension;
import code.name.monkey.retromusic.glide.RetroSimpleTarget;
import code.name.monkey.retromusic.helper.ShuffleHelper;
import code.name.monkey.retromusic.helper.StopWatch;
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader;
import code.name.monkey.retromusic.model.AbsCustomPlaylist;
import code.name.monkey.retromusic.model.Playlist;
import code.name.monkey.retromusic.model.Song;
import code.name.monkey.retromusic.providers.HistoryStore;
@ -83,57 +81,73 @@ import code.name.monkey.retromusic.service.notification.PlayingNotificationImpl2
import code.name.monkey.retromusic.service.notification.PlayingNotificationOreo;
import code.name.monkey.retromusic.service.playback.Playback;
import code.name.monkey.retromusic.util.MusicUtil;
import code.name.monkey.retromusic.util.PackageValidator;
import code.name.monkey.retromusic.util.PreferenceUtil;
import code.name.monkey.retromusic.util.RetroUtil;
import io.reactivex.schedulers.Schedulers;
import static code.name.monkey.retromusic.Constants.ACTION_PAUSE;
import static code.name.monkey.retromusic.Constants.ACTION_PENDING_QUIT;
import static code.name.monkey.retromusic.Constants.ACTION_PLAY;
import static code.name.monkey.retromusic.Constants.ACTION_PLAY_PLAYLIST;
import static code.name.monkey.retromusic.Constants.ACTION_QUIT;
import static code.name.monkey.retromusic.Constants.ACTION_REWIND;
import static code.name.monkey.retromusic.Constants.ACTION_SKIP;
import static code.name.monkey.retromusic.Constants.ACTION_STOP;
import static code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE;
import static code.name.monkey.retromusic.Constants.APP_WIDGET_UPDATE;
import static code.name.monkey.retromusic.Constants.EXTRA_APP_WIDGET_NAME;
import static code.name.monkey.retromusic.Constants.INTENT_EXTRA_PLAYLIST;
import static code.name.monkey.retromusic.Constants.INTENT_EXTRA_SHUFFLE_MODE;
import static code.name.monkey.retromusic.Constants.MEDIA_STORE_CHANGED;
import static code.name.monkey.retromusic.Constants.META_CHANGED;
import static code.name.monkey.retromusic.Constants.MUSIC_PACKAGE_NAME;
import static code.name.monkey.retromusic.Constants.PLAY_STATE_CHANGED;
import static code.name.monkey.retromusic.Constants.QUEUE_CHANGED;
import static code.name.monkey.retromusic.Constants.REPEAT_MODE_CHANGED;
import static code.name.monkey.retromusic.Constants.RETRO_MUSIC_PACKAGE_NAME;
import static code.name.monkey.retromusic.Constants.SHUFFLE_MODE_CHANGED;
/**
* @author Karim Abou Zeid (kabouzeid), Andrew Neal
*/
public class MusicService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener, Playback.PlaybackCallbacks {
public class MusicService extends MediaBrowserServiceCompat implements SharedPreferences.OnSharedPreferenceChangeListener, Playback.PlaybackCallbacks {
public static final String TAG = MusicService.class.getSimpleName();
public static final String RETRO_MUSIC_PACKAGE_NAME = "code.name.monkey.retromusic";
public static final String MUSIC_PACKAGE_NAME = "com.android.music";
public static final String ACTION_TOGGLE_PAUSE = RETRO_MUSIC_PACKAGE_NAME + ".togglepause";
public static final String ACTION_PLAY = RETRO_MUSIC_PACKAGE_NAME + ".play";
public static final String ACTION_PLAY_PLAYLIST = RETRO_MUSIC_PACKAGE_NAME + ".play.playlist";
public static final String ACTION_PAUSE = RETRO_MUSIC_PACKAGE_NAME + ".pause";
public static final String ACTION_STOP = RETRO_MUSIC_PACKAGE_NAME + ".stop";
public static final String ACTION_SKIP = RETRO_MUSIC_PACKAGE_NAME + ".skip";
public static final String ACTION_REWIND = RETRO_MUSIC_PACKAGE_NAME + ".rewind";
public static final String ACTION_QUIT = RETRO_MUSIC_PACKAGE_NAME + ".quitservice";
public static final String ACTION_PENDING_QUIT = RETRO_MUSIC_PACKAGE_NAME + ".pendingquitservice";
public static final String INTENT_EXTRA_PLAYLIST = RETRO_MUSIC_PACKAGE_NAME + "intentextra.playlist";
public static final String INTENT_EXTRA_SHUFFLE_MODE = RETRO_MUSIC_PACKAGE_NAME + ".intentextra.shufflemode";
public static final String APP_WIDGET_UPDATE = RETRO_MUSIC_PACKAGE_NAME + ".appwidgetupdate";
public static final String EXTRA_APP_WIDGET_NAME = RETRO_MUSIC_PACKAGE_NAME + "app_widget_name";
// Do not change these three strings as it will break support with other apps (e.g. last.fm scrobbling)
public static final String META_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".metachanged";
public static final String QUEUE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".queuechanged";
public static final String PLAY_STATE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".playstatechanged";
public static final String FAVORITE_STATE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + "favoritestatechanged";
public static final String REPEAT_MODE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".repeatmodechanged";
public static final String SHUFFLE_MODE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".shufflemodechanged";
public static final String MEDIA_STORE_CHANGED = RETRO_MUSIC_PACKAGE_NAME + ".mediastorechanged";
public static final String CYCLE_REPEAT = RETRO_MUSIC_PACKAGE_NAME + ".cyclerepeat";
public static final String TOGGLE_SHUFFLE = RETRO_MUSIC_PACKAGE_NAME + ".toggleshuffle";
public static final String TOGGLE_FAVORITE = RETRO_MUSIC_PACKAGE_NAME + ".togglefavorite";
public static final String SAVED_POSITION = "POSITION";
public static final String SAVED_POSITION_IN_TRACK = "POSITION_IN_TRACK";
public static final String SAVED_SHUFFLE_MODE = "SHUFFLE_MODE";
public static final String SAVED_REPEAT_MODE = "REPEAT_MODE";
public static final int RELEASE_WAKELOCK = 0;
public static final int TRACK_ENDED = 1;
public static final int TRACK_WENT_TO_NEXT = 2;
public static final int PLAY_SONG = 3;
public static final int PREPARE_NEXT = 4;
public static final int SET_POSITION = 5;
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;
public static final int REPEAT_MODE_NONE = 0;
public static final int REPEAT_MODE_ALL = 1;
public static final int REPEAT_MODE_THIS = 2;
public static final int SAVE_QUEUES = 0;
private static final int FOCUS_CHANGE = 6;
private static final int DUCK = 7;
private static final int UNDUCK = 8;
private static final long MEDIA_SESSION_ACTIONS = PlaybackStateCompat.ACTION_PLAY
| PlaybackStateCompat.ACTION_PAUSE
| PlaybackStateCompat.ACTION_PLAY_PAUSE
@ -143,6 +157,9 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
| PlaybackStateCompat.ACTION_SEEK_TO;
private final IBinder musicBind = new MusicBinder();
public boolean pendingQuit = false;
public Playback playback;
public int position = -1;
public int nextPosition = -1;
private AppWidgetBig appWidgetBig = AppWidgetBig.Companion.getInstance();
private AppWidgetClassic appWidgetClassic = AppWidgetClassic.Companion.getInstance();
private AppWidgetSmall appWidgetSmall = AppWidgetSmall.Companion.getInstance();
@ -179,11 +196,8 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
}
};
private Playback playback;
private ArrayList<Song> playingQueue = new ArrayList<>();
private ArrayList<Song> originalPlayingQueue = new ArrayList<>();
private int position = -1;
private int nextPosition = -1;
private int shuffleMode;
private int repeatMode;
private boolean queuesRestored;
@ -198,7 +212,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
};
private PlayingNotification playingNotification;
private AudioManager audioManager;
@SuppressWarnings("deprecation")
private MediaSessionCompat mediaSession;
private PowerManager.WakeLock wakeLock;
private PlaybackHandler playerHandler;
@ -235,7 +248,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
super.onCallStateChanged(state, incomingNumber);
}
};
private boolean isServiceBound;
private Handler uiThreadHandler;
private IntentFilter headsetReceiverIntentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
private boolean headsetReceiverRegistered = false;
@ -260,6 +272,8 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
}
}
};
private PackageValidator mPackageValidator;
private AutoMusicProvider mMusicProvider;
private static String getTrackUri(@NonNull Song song) {
return MusicUtil.getSongFileUri(song.getId()).toString();
@ -278,7 +292,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
}
}
@Override
public void onCreate() {
super.onCreate();
@ -314,8 +327,8 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
initNotification();
mediaStoreObserver = new MediaStoreObserver(playerHandler);
throttledSeekHandler = new ThrottledSeekHandler(playerHandler);
mediaStoreObserver = new MediaStoreObserver(this, playerHandler);
throttledSeekHandler = new ThrottledSeekHandler(this, playerHandler);
getContentResolver().registerContentObserver(
MediaStore.Audio.Media.INTERNAL_CONTENT_URI, true, mediaStoreObserver);
getContentResolver().registerContentObserver(
@ -324,14 +337,11 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
PreferenceUtil.getInstance().registerOnSharedPreferenceChangedListener(this);
restoreState();
mediaSession.setActive(true);
mPackageValidator = new PackageValidator(this, R.xml.allowed_media_browser_callers);
mMusicProvider = new AutoMusicProvider(this);
sendBroadcast(new Intent("code.name.monkey.retromusic.RETRO_MUSIC_SERVICE_CREATED"));
registerHeadsetEvents();
}
private AudioManager getAudioManager() {
@ -354,50 +364,14 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
"RetroMusicPlayer",
mediaButtonReceiverComponentName,
mediaButtonReceiverPendingIntent);
mediaSession.setCallback(new MediaSessionCompat.Callback() {
@Override
public void onPlay() {
play();
}
@Override
public void onPause() {
pause();
}
@Override
public void onSkipToNext() {
playNextSong(true);
}
@Override
public void onSkipToPrevious() {
back(true);
}
@Override
public void onStop() {
quit();
}
@Override
public void onSeekTo(long pos) {
seek((int) pos);
updateMediaSessionPlaybackState();
}
@Override
public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
return MediaButtonIntentReceiver.Companion.handleIntent(MusicService.this, mediaButtonEvent);
}
});
MediaSessionCallback mediasessionCallback = new MediaSessionCallback(getApplicationContext(), this);
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
| MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
);
mediaSession.setCallback(mediasessionCallback);
mediaSession.setActive(true);
mediaSession.setMediaButtonReceiver(mediaButtonReceiverPendingIntent);
setSessionToken(mediaSession.getSessionToken());
}
@Override
@ -437,6 +411,9 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
case ACTION_PENDING_QUIT:
pendingQuit = true;
break;
case TOGGLE_FAVORITE:
MusicUtil.toggleFavorite(getApplicationContext(), getCurrentSong());
break;
}
}
}
@ -447,22 +424,21 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
private void playFromPlaylist(Intent intent) {
Playlist playlist = intent.getParcelableExtra(INTENT_EXTRA_PLAYLIST);
int shuffleMode = intent.getIntExtra(INTENT_EXTRA_SHUFFLE_MODE, getShuffleMode());
if (playlist != null) {
if (playlist instanceof AbsCustomPlaylist) {
((AbsCustomPlaylist) playlist).getSongs(getApplicationContext())
.subscribeOn(Schedulers.io())
.subscribe(songs -> {
playSongs(shuffleMode, songs);
}, throwable -> {
});
ArrayList<Song> playlistSongs = playlist.getSongs(getApplicationContext());
if (!playlistSongs.isEmpty()) {
if (shuffleMode == SHUFFLE_MODE_SHUFFLE) {
int startPosition = 0;
if (!playlistSongs.isEmpty()) {
startPosition = new Random().nextInt(playlistSongs.size());
}
openQueue(playlistSongs, startPosition, true);
setShuffleMode(shuffleMode);
} else {
openQueue(playlistSongs, 0, true);
}
} else {
PlaylistSongsLoader.INSTANCE.getPlaylistSongList(getApplicationContext(), playlist.id)
.subscribeOn(Schedulers.io())
.subscribe(songs -> {
playSongs(shuffleMode, songs);
}, throwable -> {
});
Toast.makeText(getApplicationContext(), R.string.playlist_is_empty, Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(getApplicationContext(), R.string.playlist_is_empty, Toast.LENGTH_LONG).show();
@ -507,25 +483,43 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
@Override
public IBinder onBind(Intent intent) {
isServiceBound = true;
return musicBind;
}
@Nullable
@Override
public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) {
if (!mPackageValidator.isKnownCaller(clientPackageName, clientUid)) {
return new BrowserRoot(AutoMediaIDHelper.MEDIA_ID_EMPTY_ROOT, null);
}
return new BrowserRoot(AutoMediaIDHelper.MEDIA_ID_ROOT, null);
}
@Override
public void onLoadChildren(@NonNull String parentId, @NonNull Result<List<MediaBrowserCompat.MediaItem>> result) {
if (AutoMediaIDHelper.MEDIA_ID_EMPTY_ROOT.equals(parentId)) {
result.sendResult(new ArrayList<>());
} else if (mMusicProvider.isInitialized()) {
result.sendResult(mMusicProvider.getChildren(parentId, getResources()));
} else {
result.detach();
mMusicProvider.retrieveMediaAsync(success -> result.sendResult(mMusicProvider.getChildren(parentId, getResources())));
}
}
@Override
public void onRebind(Intent intent) {
isServiceBound = true;
}
@Override
public boolean onUnbind(Intent intent) {
isServiceBound = false;
if (!isPlaying()) {
stopSelf();
}
return true;
}
private void saveQueuesImpl() {
public void saveQueuesImpl() {
MusicPlaybackQueueStore.getInstance(this).saveQueues(playingQueue, originalPlayingQueue);
}
@ -533,7 +527,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
PreferenceManager.getDefaultSharedPreferences(this).edit().putInt(SAVED_POSITION, getPosition()).apply();
}
private void savePositionInTrack() {
public void savePositionInTrack() {
PreferenceManager.getDefaultSharedPreferences(this).edit().putInt(SAVED_POSITION_IN_TRACK, getSongProgressMillis()).apply();
}
@ -558,14 +552,10 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
playerHandler.sendEmptyMessage(RESTORE_QUEUES);
}
private synchronized void restoreQueuesAndPositionIfNecessary() {
public synchronized void restoreQueuesAndPositionIfNecessary() {
if (!queuesRestored && playingQueue.isEmpty()) {
ArrayList<Song> restoredQueue = MusicPlaybackQueueStore.getInstance(this).getSavedPlayingQueue()
.blockingFirst();
ArrayList<Song> restoredOriginalQueue = MusicPlaybackQueueStore.getInstance(this).getSavedOriginalPlayingQueue()
.blockingFirst();
ArrayList<Song> restoredQueue = MusicPlaybackQueueStore.getInstance(this).getSavedPlayingQueue();
ArrayList<Song> restoredOriginalQueue = MusicPlaybackQueueStore.getInstance(this).getSavedOriginalPlayingQueue();
int restoredPosition = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_POSITION, -1);
int restoredPositionInTrack = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_POSITION_IN_TRACK, -1);
@ -587,20 +577,16 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
queuesRestored = true;
}
private int quit() {
public void quit() {
pause();
playingNotification.stop();
if (isServiceBound) {
return START_STICKY;
} else {
closeAudioEffectSession();
getAudioManager().abandonAudioFocus(audioFocusListener);
stopSelf();
return START_NOT_STICKY;
}
closeAudioEffectSession();
getAudioManager().abandonAudioFocus(audioFocusListener);
stopSelf();
}
private void releaseResources() {
playerHandler.removeCallbacksAndMessages(null);
musicPlayerHandlerThread.quitSafely();
@ -629,7 +615,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
playSongAt(getNextPosition(force));
}
private boolean openTrackAndPrepareNextAt(int position) {
public boolean openTrackAndPrepareNextAt(int position) {
synchronized (this) {
this.position = position;
boolean prepared = openCurrent();
@ -655,7 +641,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
playerHandler.obtainMessage(PREPARE_NEXT).sendToTarget();
}
private boolean prepareNextImpl() {
public boolean prepareNextImpl() {
synchronized (this) {
try {
int nextPosition = getNextPosition(false);
@ -694,13 +680,14 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
}
}
private void updateMediaSessionPlaybackState() {
mediaSession.setPlaybackState(
new PlaybackStateCompat.Builder()
.setActions(MEDIA_SESSION_ACTIONS)
.setState(isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED,
getSongProgressMillis(), 1)
.build());
public void updateMediaSessionPlaybackState() {
PlaybackStateCompat.Builder stateBuilder = new PlaybackStateCompat.Builder()
.setActions(MEDIA_SESSION_ACTIONS)
.setState(isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED,
getSongProgressMillis(), 1);
mediaSession.setPlaybackState(stateBuilder.build());
}
private void updateMediaSessionMetaData() {
@ -801,7 +788,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
return position;
}
private boolean isLastTrack() {
public boolean isLastTrack() {
return getPosition() == getPlayingQueue().size() - 1;
}
@ -946,7 +933,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
playerHandler.obtainMessage(PLAY_SONG, position, 0).sendToTarget();
}
private void playSongAtImpl(int position) {
public void playSongAtImpl(int position) {
if (openTrackAndPrepareNextAt(position)) {
play();
} else {
@ -1128,18 +1115,18 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
notifyChange(QUEUE_CHANGED);
}
private void notifyChange(@NonNull final String what) {
public void notifyChange(@NonNull final String what) {
handleAndSendChangeInternal(what);
sendPublicIntent(what);
}
private void handleAndSendChangeInternal(@NonNull final String what) {
public void handleAndSendChangeInternal(@NonNull final String what) {
handleChangeInternal(what);
sendChangeInternal(what);
}
// to let other apps know whats playing. i.E. last.fm (scrobbling) or musixmatch
private void sendPublicIntent(@NonNull final String what) {
public void sendPublicIntent(@NonNull final String what) {
final Intent intent = new Intent(what.replace(RETRO_MUSIC_PACKAGE_NAME, MUSIC_PACKAGE_NAME));
final Song song = getCurrentSong();
@ -1266,187 +1253,12 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
playerHandler.sendEmptyMessage(TRACK_ENDED);
}
private static final class QueueSaveHandler extends Handler {
@NonNull
private final WeakReference<MusicService> mService;
QueueSaveHandler(final MusicService service, @NonNull final Looper looper) {
super(looper);
mService = new WeakReference<>(service);
}
@Override
public void handleMessage(@NonNull Message msg) {
final MusicService service = mService.get();
if (msg.what == SAVE_QUEUES) {
service.saveQueuesImpl();
}
}
public boolean isPausedByTransientLossOfFocus() {
return pausedByTransientLossOfFocus;
}
private static final class PlaybackHandler extends Handler {
@NonNull
private final WeakReference<MusicService> mService;
private float currentDuckVolume = 1.0f;
PlaybackHandler(final MusicService service, @NonNull final Looper looper) {
super(looper);
mService = new WeakReference<>(service);
}
@Override
public void handleMessage(@NonNull final Message msg) {
final MusicService service = mService.get();
if (service == null) {
return;
}
switch (msg.what) {
case DUCK:
if (PreferenceUtil.getInstance().audioDucking()) {
currentDuckVolume -= .05f;
if (currentDuckVolume > .2f) {
sendEmptyMessageDelayed(DUCK, 10);
} else {
currentDuckVolume = .2f;
}
} else {
currentDuckVolume = 1f;
}
service.playback.setVolume(currentDuckVolume);
break;
case UNDUCK:
if (PreferenceUtil.getInstance().audioDucking()) {
currentDuckVolume += .03f;
if (currentDuckVolume < 1f) {
sendEmptyMessageDelayed(UNDUCK, 10);
} else {
currentDuckVolume = 1f;
}
} else {
currentDuckVolume = 1f;
}
service.playback.setVolume(currentDuckVolume);
break;
case TRACK_WENT_TO_NEXT:
if (service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) {
service.pause();
service.seek(0);
} else {
service.position = service.nextPosition;
service.prepareNextImpl();
service.notifyChange(META_CHANGED);
}
break;
case TRACK_ENDED:
// if there is a timer finished, don't continue
if (service.pendingQuit ||
service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) {
service.notifyChange(PLAY_STATE_CHANGED);
service.seek(0);
if (service.pendingQuit) {
service.pendingQuit = false;
service.quit();
break;
}
} else {
service.playNextSong(false);
}
sendEmptyMessage(RELEASE_WAKELOCK);
break;
case RELEASE_WAKELOCK:
service.releaseWakeLock();
break;
case PLAY_SONG:
service.playSongAtImpl(msg.arg1);
break;
case SET_POSITION:
service.openTrackAndPrepareNextAt(msg.arg1);
service.notifyChange(PLAY_STATE_CHANGED);
break;
case PREPARE_NEXT:
service.prepareNextImpl();
break;
case RESTORE_QUEUES:
service.restoreQueuesAndPositionIfNecessary();
break;
case FOCUS_CHANGE:
switch (msg.arg1) {
case AudioManager.AUDIOFOCUS_GAIN:
if (!service.isPlaying() && service.pausedByTransientLossOfFocus) {
service.play();
service.pausedByTransientLossOfFocus = false;
}
removeMessages(DUCK);
sendEmptyMessage(UNDUCK);
break;
case AudioManager.AUDIOFOCUS_LOSS:
// Lost focus for an unbounded amount of time: stop playback and release media playback
service.pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
// Lost focus for a short time, but we have to stop
// playback. We don't release the media playback because playback
// is likely to resume
boolean wasPlaying = service.isPlaying();
service.pause();
service.pausedByTransientLossOfFocus = wasPlaying;
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// Lost focus for a short time, but it's ok to keep playing
// at an attenuated level
removeMessages(UNDUCK);
sendEmptyMessage(DUCK);
break;
}
break;
}
}
}
private static class SongPlayCountHelper {
public static final String TAG = SongPlayCountHelper.class.getSimpleName();
private StopWatch stopWatch = new StopWatch();
private Song song = Song.getEmptySong();
public Song getSong() {
return song;
}
boolean shouldBumpPlayCount() {
return song.getDuration() * 0.5d < stopWatch.getElapsedTime();
}
void notifySongChanged(Song song) {
synchronized (this) {
stopWatch.reset();
this.song = song;
}
}
void notifyPlayStateChanged(boolean isPlaying) {
synchronized (this) {
if (isPlaying) {
stopWatch.start();
} else {
stopWatch.pause();
}
}
}
public void setPausedByTransientLossOfFocus(boolean pausedByTransientLossOfFocus) {
this.pausedByTransientLossOfFocus = pausedByTransientLossOfFocus;
}
public class MusicBinder extends Binder {
@ -1455,52 +1267,4 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
return MusicService.this;
}
}
private class MediaStoreObserver extends ContentObserver implements Runnable {
// milliseconds to delay before calling refresh to aggregate events
private static final long REFRESH_DELAY = 500;
private Handler mHandler;
MediaStoreObserver(Handler handler) {
super(handler);
mHandler = handler;
}
@Override
public void onChange(boolean selfChange) {
// if a change is detected, remove any scheduled callback
// then post a new one. This is intended to prevent closely
// spaced events from generating multiple refresh calls
mHandler.removeCallbacks(this);
mHandler.postDelayed(this, REFRESH_DELAY);
}
@Override
public void run() {
// actually call refresh when the delayed callback fires
// do not send a sticky broadcast here
handleAndSendChangeInternal(MEDIA_STORE_CHANGED);
}
}
private class ThrottledSeekHandler implements Runnable {
// milliseconds to throttle before calling run() to aggregate events
private static final long THROTTLE = 500;
private Handler mHandler;
ThrottledSeekHandler(Handler handler) {
mHandler = handler;
}
void notifySeek() {
mHandler.removeCallbacks(this);
mHandler.postDelayed(this, THROTTLE);
}
@Override
public void run() {
savePositionInTrack();
sendPublicIntent(PLAY_STATE_CHANGED); // for musixmatch synced lyrics
}
}
}

View file

@ -0,0 +1,165 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.service;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import androidx.annotation.NonNull;
import java.lang.ref.WeakReference;
import code.name.monkey.retromusic.util.PreferenceUtil;
import static code.name.monkey.retromusic.service.MusicService.DUCK;
import static code.name.monkey.retromusic.service.MusicService.META_CHANGED;
import static code.name.monkey.retromusic.service.MusicService.PLAY_STATE_CHANGED;
import static code.name.monkey.retromusic.service.MusicService.REPEAT_MODE_NONE;
import static code.name.monkey.retromusic.service.MusicService.TRACK_ENDED;
import static code.name.monkey.retromusic.service.MusicService.TRACK_WENT_TO_NEXT;
class PlaybackHandler extends Handler {
@NonNull
private final WeakReference<MusicService> mService;
private float currentDuckVolume = 1.0f;
PlaybackHandler(final MusicService service, @NonNull final Looper looper) {
super(looper);
mService = new WeakReference<>(service);
}
@Override
public void handleMessage(@NonNull final Message msg) {
final MusicService service = mService.get();
if (service == null) {
return;
}
switch (msg.what) {
case MusicService.DUCK:
if (PreferenceUtil.getInstance().audioDucking()) {
currentDuckVolume -= .05f;
if (currentDuckVolume > .2f) {
sendEmptyMessageDelayed(DUCK, 10);
} else {
currentDuckVolume = .2f;
}
} else {
currentDuckVolume = 1f;
}
service.playback.setVolume(currentDuckVolume);
break;
case MusicService.UNDUCK:
if (PreferenceUtil.getInstance().audioDucking()) {
currentDuckVolume += .03f;
if (currentDuckVolume < 1f) {
sendEmptyMessageDelayed(MusicService.UNDUCK, 10);
} else {
currentDuckVolume = 1f;
}
} else {
currentDuckVolume = 1f;
}
service.playback.setVolume(currentDuckVolume);
break;
case TRACK_WENT_TO_NEXT:
if (service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) {
service.pause();
service.seek(0);
} else {
service.position = service.nextPosition;
service.prepareNextImpl();
service.notifyChange(META_CHANGED);
}
break;
case TRACK_ENDED:
// if there is a timer finished, don't continue
if (service.pendingQuit ||
service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) {
service.notifyChange(PLAY_STATE_CHANGED);
service.seek(0);
if (service.pendingQuit) {
service.pendingQuit = false;
service.quit();
break;
}
} else {
service.playNextSong(false);
}
sendEmptyMessage(MusicService.RELEASE_WAKELOCK);
break;
case MusicService.RELEASE_WAKELOCK:
service.releaseWakeLock();
break;
case MusicService.PLAY_SONG:
service.playSongAtImpl(msg.arg1);
break;
case MusicService.SET_POSITION:
service.openTrackAndPrepareNextAt(msg.arg1);
service.notifyChange(PLAY_STATE_CHANGED);
break;
case MusicService.PREPARE_NEXT:
service.prepareNextImpl();
break;
case MusicService.RESTORE_QUEUES:
service.restoreQueuesAndPositionIfNecessary();
break;
case MusicService.FOCUS_CHANGE:
switch (msg.arg1) {
case AudioManager.AUDIOFOCUS_GAIN:
if (!service.isPlaying() && service.isPausedByTransientLossOfFocus()) {
service.play();
service.setPausedByTransientLossOfFocus(false);
}
removeMessages(DUCK);
sendEmptyMessage(MusicService.UNDUCK);
break;
case AudioManager.AUDIOFOCUS_LOSS:
// Lost focus for an unbounded amount of time: stop playback and release media playback
service.pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
// Lost focus for a short time, but we have to stop
// playback. We don't release the media playback because playback
// is likely to resume
boolean wasPlaying = service.isPlaying();
service.pause();
service.setPausedByTransientLossOfFocus(wasPlaying);
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// Lost focus for a short time, but it's ok to keep playing
// at an attenuated level
removeMessages(MusicService.UNDUCK);
sendEmptyMessage(DUCK);
break;
}
break;
}
}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.service;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import androidx.annotation.NonNull;
import java.lang.ref.WeakReference;
import static code.name.monkey.retromusic.service.MusicService.SAVE_QUEUES;
class QueueSaveHandler extends Handler {
@NonNull
private final WeakReference<MusicService> mService;
QueueSaveHandler(final MusicService service, @NonNull final Looper looper) {
super(looper);
mService = new WeakReference<>(service);
}
@Override
public void handleMessage(@NonNull Message msg) {
final MusicService service = mService.get();
if (msg.what == SAVE_QUEUES) {
service.saveQueuesImpl();
}
}
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.service;
import code.name.monkey.retromusic.helper.StopWatch;
import code.name.monkey.retromusic.model.Song;
public class SongPlayCountHelper {
public static final String TAG = SongPlayCountHelper.class.getSimpleName();
private StopWatch stopWatch = new StopWatch();
private Song song = Song.getEmptySong();
public Song getSong() {
return song;
}
boolean shouldBumpPlayCount() {
return song.getDuration() * 0.5d < stopWatch.getElapsedTime();
}
void notifySongChanged(Song song) {
synchronized (this) {
stopWatch.reset();
this.song = song;
}
}
void notifyPlayStateChanged(boolean isPlaying) {
synchronized (this) {
if (isPlaying) {
stopWatch.start();
} else {
stopWatch.pause();
}
}
}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.service;
import android.os.Handler;
import static code.name.monkey.retromusic.service.MusicService.PLAY_STATE_CHANGED;
public class ThrottledSeekHandler implements Runnable {
// milliseconds to throttle before calling run() to aggregate events
private static final long THROTTLE = 500;
private final MusicService musicService;
private Handler handler;
ThrottledSeekHandler(MusicService musicService, Handler handler) {
this.musicService = musicService;
this.handler = handler;
}
void notifySeek() {
handler.removeCallbacks(this);
handler.postDelayed(this, THROTTLE);
}
@Override
public void run() {
musicService.savePositionInTrack();
musicService.sendPublicIntent(PLAY_STATE_CHANGED); // for musixmatch synced lyrics
}
}

View file

@ -24,12 +24,13 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.service.media.MediaBrowserService;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.List;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
import code.name.monkey.retromusic.loaders.AlbumLoader;
@ -194,7 +195,7 @@ public class WearBrowserService extends MediaBrowserService {
} else {
switch (Integer.parseInt(Character.toString(parentId.charAt(0)))) {
case TYPE_ARTIST:
List<Artist> artistList = ArtistLoader.INSTANCE.getAllArtists(mContext).blockingFirst();
List<Artist> artistList = ArtistLoader.INSTANCE.getAllArtists(mContext) ;
for (Artist artist : artistList) {
String albumNmber = String.format("%d %s", artist.getAlbums().size(), artist.getAlbums().size() > 1 ? "Albums" : "Album");
String songCount = String.format("%d %s", artist.getSongs().size(), artist.getSongs().size() > 1 ? "Songs" : "Song");
@ -215,7 +216,7 @@ public class WearBrowserService extends MediaBrowserService {
Uri.parse("android.resource://code.name.monkey.retromusic/drawable/default_artist_art"),
MediaBrowser.MediaItem.FLAG_BROWSABLE);
List<Album> artistAlbums = ArtistLoader.INSTANCE.getArtist(mContext, Integer.parseInt(parentId.substring(1))).blockingFirst().getAlbums(); //ArtistAlbumLoader.getAlbumsForArtist(mContext, Long.parseLong(parentId.substring(1)));
List<Album> artistAlbums = ArtistLoader.INSTANCE.getArtist(mContext, Integer.parseInt(parentId.substring(1))).getAlbums(); //ArtistAlbumLoader.getAlbumsForArtist(mContext, Long.parseLong(parentId.substring(1)));
for (Album album : artistAlbums) {
String songCount = String.format("%d %s", album.getSongs().size(), album.getSongs().size() > 1 ? "Songs" : "Song");
fillMediaItems(mediaItems,
@ -227,7 +228,7 @@ public class WearBrowserService extends MediaBrowserService {
}
break;
case TYPE_ALBUM:
List<Album> albumList = AlbumLoader.Companion.getAllAlbums(mContext).blockingFirst();
List<Album> albumList = AlbumLoader.INSTANCE.getAllAlbums(mContext);
for (Album album : albumList) {
fillMediaItems(mediaItems,
Integer.toString(TYPE_ALBUM_SONGS) + Long.toString(album.getId()),
@ -238,7 +239,7 @@ public class WearBrowserService extends MediaBrowserService {
}
break;
case TYPE_SONG:
List<Song> songList = SongLoader.INSTANCE.getAllSongs(mContext).blockingFirst();
List<Song> songList = SongLoader.INSTANCE.getAllSongs(mContext);
for (Song song : songList) {
fillMediaItems(mediaItems,
String.valueOf(song.getId()),
@ -250,7 +251,7 @@ public class WearBrowserService extends MediaBrowserService {
break;
case TYPE_ALBUM_SONGS:
List<Song> albumSongList = AlbumLoader.Companion.getAlbum(mContext, Integer.parseInt(parentId.substring(1))).blockingFirst().getSongs();
List<Song> albumSongList = AlbumLoader.INSTANCE.getAlbum(mContext, Integer.parseInt(parentId.substring(1))).getSongs();
for (Song song : albumSongList) {
fillMediaItems(mediaItems,
String.valueOf(song.getId()),
@ -261,7 +262,7 @@ public class WearBrowserService extends MediaBrowserService {
}
break;
case TYPE_ARTIST_ALL_SONGS:
List<Song> artistSongs = ArtistLoader.INSTANCE.getArtist(mContext, Integer.parseInt(parentId.substring(1))).blockingFirst().getSongs();
List<Song> artistSongs = ArtistLoader.INSTANCE.getArtist(mContext, Integer.parseInt(parentId.substring(1))).getSongs();
for (Song song : artistSongs) {
fillMediaItems(mediaItems,
String.valueOf(song.getId()),
@ -272,9 +273,9 @@ public class WearBrowserService extends MediaBrowserService {
}
break;
case TYPE_PLAYLIST:
List<Playlist> playlistList = PlaylistLoader.INSTANCE.getAllPlaylists(mContext).blockingFirst();
List<Playlist> playlistList = PlaylistLoader.INSTANCE.getAllPlaylists(mContext);
for (Playlist playlist : playlistList) {
int size = PlaylistSongsLoader.INSTANCE.getPlaylistSongList(mContext, playlist).blockingFirst().size();
int size = PlaylistSongsLoader.INSTANCE.getPlaylistSongList(mContext, playlist).size();
String songCount = String.format("%d %s", size, size > 1 ? "Songs" : "Song");
fillMediaItems(mediaItems,
Integer.toString(TYPE_PLAYLIST_ALL_SONGS) + Long.toString(playlist.id),
@ -285,7 +286,7 @@ public class WearBrowserService extends MediaBrowserService {
}
break;
case TYPE_PLAYLIST_ALL_SONGS:
List<Song> playlistSongs = PlaylistSongsLoader.INSTANCE.getPlaylistSongList(mContext, Integer.parseInt(parentId.substring(1))).blockingFirst();
List<Song> playlistSongs = PlaylistSongsLoader.INSTANCE.getPlaylistSongList(mContext, Integer.parseInt(parentId.substring(1)));
for (Song song : playlistSongs) {
fillMediaItems(mediaItems,
String.valueOf(song.getId()),
@ -326,7 +327,7 @@ public class WearBrowserService extends MediaBrowserService {
long songId = Long.parseLong(mediaId);
setSessionActive();
ArrayList<Song> songs = new ArrayList<>();
songs.add(SongLoader.INSTANCE.getSong(mContext, Integer.parseInt(mediaId)).blockingFirst());
songs.add(SongLoader.INSTANCE.getSong(mContext, Integer.parseInt(mediaId)));
MusicPlayerRemote.INSTANCE.openQueue(songs, 0, true);
}

View file

@ -28,10 +28,6 @@ import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.Constants.ACTION_QUIT
import code.name.monkey.retromusic.Constants.ACTION_REWIND
import code.name.monkey.retromusic.Constants.ACTION_SKIP
import code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget.Companion.createBitmap
@ -40,6 +36,7 @@ import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroSimpleTarget
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.*
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.RetroUtil

View file

@ -24,17 +24,15 @@ import android.graphics.drawable.Drawable
import android.os.Build
import android.text.Html
import androidx.core.app.NotificationCompat
import code.name.monkey.retromusic.Constants.ACTION_QUIT
import code.name.monkey.retromusic.Constants.ACTION_REWIND
import code.name.monkey.retromusic.Constants.ACTION_SKIP
import code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroSimpleTarget
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.service.MusicService.*
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import com.bumptech.glide.request.target.Target
@ -48,12 +46,18 @@ class PlayingNotificationImpl24 : PlayingNotification() {
val song = service.currentSong
val isPlaying = service.isPlaying
val isFavorite = MusicUtil.isFavorite(service, song)
val playButtonResId = if (isPlaying)
R.drawable.ic_pause_white_24dp
else
R.drawable.ic_play_arrow_white_32dp
val favoriteResId = if (isFavorite)
R.drawable.ic_favorite_white_24dp
else
R.drawable.ic_favorite_border_white_24dp
val action = Intent(service, MainActivity::class.java)
action.putExtra("expand", true)
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
@ -93,6 +97,12 @@ class PlayingNotificationImpl24 : PlayingNotification() {
if (bitmapFinal == null) {
bitmapFinal = BitmapFactory.decodeResource(service.resources, R.drawable.default_album_art)
}
val toggleFavorite = NotificationCompat.Action(favoriteResId,
service.getString(R.string.action_toggle_favorite),
retrievePlaybackAction(TOGGLE_FAVORITE))
val playPauseAction = NotificationCompat.Action(
playButtonResId,
service.getString(R.string.action_play_pause),
@ -114,7 +124,7 @@ class PlayingNotificationImpl24 : PlayingNotification() {
retrievePlaybackAction(ACTION_SKIP))
val builder = NotificationCompat.Builder(service,
PlayingNotification.NOTIFICATION_CHANNEL_ID)
NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setLargeIcon(bitmapFinal)
.setContentIntent(clickIntent)

View file

@ -25,10 +25,6 @@ import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.Constants.ACTION_QUIT
import code.name.monkey.retromusic.Constants.ACTION_REWIND
import code.name.monkey.retromusic.Constants.ACTION_SKIP
import code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.glide.GlideApp
@ -37,6 +33,7 @@ import code.name.monkey.retromusic.glide.RetroSimpleTarget
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.*
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.RetroUtil.createBitmap
@ -155,14 +152,14 @@ class PlayingNotificationOreo : PlayingNotification() {
val primary = MaterialValueHelper.getPrimaryTextColor(service, dark)
val secondary = MaterialValueHelper.getSecondaryTextColor(service, dark)
val close = createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_close_white_24dp, primary)!!, PlayingNotification.NOTIFICATION_CONTROLS_SIZE_MULTIPLIER)
val prev = createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, primary)!!, PlayingNotification.NOTIFICATION_CONTROLS_SIZE_MULTIPLIER)
val next = createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, primary)!!, PlayingNotification.NOTIFICATION_CONTROLS_SIZE_MULTIPLIER)
val close = createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_close_white_24dp, primary)!!, NOTIFICATION_CONTROLS_SIZE_MULTIPLIER)
val prev = createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, primary)!!, NOTIFICATION_CONTROLS_SIZE_MULTIPLIER)
val next = createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, primary)!!, NOTIFICATION_CONTROLS_SIZE_MULTIPLIER)
val playPause = createBitmap(RetroUtil.getTintedVectorDrawable(service,
if (isPlaying)
R.drawable.ic_pause_white_24dp
else
R.drawable.ic_play_arrow_white_32dp, primary)!!, PlayingNotification.NOTIFICATION_CONTROLS_SIZE_MULTIPLIER)
R.drawable.ic_play_arrow_white_32dp, primary)!!, NOTIFICATION_CONTROLS_SIZE_MULTIPLIER)
notificationLayout.setTextColor(R.id.title, primary)
notificationLayout.setTextColor(R.id.subtitle, secondary)