diff --git a/app/src/main/java/com/kabouzeid/gramophone/App.java b/app/src/main/java/com/kabouzeid/gramophone/App.java index 0405ef0d..bd4d5d16 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/App.java +++ b/app/src/main/java/com/kabouzeid/gramophone/App.java @@ -30,10 +30,13 @@ public class App extends Application { public void onCreate() { super.onCreate(); if (!BuildConfig.DEBUG) Fabric.with(this, new Crashlytics()); - MusicPlayerRemote.init(this); + + MusicPlayerRemote.startAndBindService(this); + ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this).build(); ImageLoader.getInstance().init(config); L.writeLogs(false); // turns off UILs annoying LogCat output + TagOptionSingleton.getInstance().isAndroid(); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java b/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java index cdf6bb61..261dfb1c 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java +++ b/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java @@ -5,18 +5,13 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.media.audiofx.AudioEffect; -import android.net.Uri; import android.os.IBinder; -import android.preference.PreferenceManager; -import android.util.Log; import android.widget.Toast; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.loader.SongLoader; -import com.kabouzeid.gramophone.misc.AppKeys; import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.service.MusicService; -import com.kabouzeid.gramophone.util.InternalStorageUtil; import java.util.ArrayList; import java.util.List; @@ -27,25 +22,18 @@ import java.util.Random; */ public class MusicPlayerRemote { - private static final String TAG = MusicPlayerRemote.class.getSimpleName(); + public static final String TAG = MusicPlayerRemote.class.getSimpleName(); - private static int position = -1; - private static boolean startAfterConnected = false; + public static final String SERVICE_BOUND = "com.kabouzeid.gramophone.SERVICE_BOUND"; - private static ArrayList playingQueue; - private static ArrayList restoredOriginalQueue; - - private static Context context; private static MusicService musicService; - private static Intent musicServiceIntent; private static final ServiceConnection musicConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { MusicService.MusicBinder binder = (MusicService.MusicBinder) service; musicService = binder.getService(); - musicService.restorePreviousState(restoredOriginalQueue, playingQueue, position); - if (startAfterConnected) resumePlaying(); + musicService.sendBroadcast(new Intent(SERVICE_BOUND)); } @Override @@ -54,20 +42,14 @@ public class MusicPlayerRemote { } }; - public static void init(final Context context) { - MusicPlayerRemote.context = context; - playingQueue = new ArrayList<>(); - restoredOriginalQueue = new ArrayList<>(); - startAndBindService(); - restorePreviousState(); + public static void startAndBindService(final Context context) { + Intent musicServiceIntent = new Intent(context, MusicService.class); + context.bindService(musicServiceIntent, musicConnection, Context.BIND_AUTO_CREATE); + context.startService(musicServiceIntent); } - private static void startAndBindService() { - if (musicServiceIntent == null) { - musicServiceIntent = new Intent(context, MusicService.class); - context.bindService(musicServiceIntent, musicConnection, Context.BIND_AUTO_CREATE); - context.startService(musicServiceIntent); - } + public static boolean isServiceConnected() { + return musicService != null; } public static void playSongAt(final int position) { @@ -111,11 +93,8 @@ public class MusicPlayerRemote { } public static void openQueue(final ArrayList playingQueue, final int startPosition, final boolean startPlaying) { - MusicPlayerRemote.playingQueue = playingQueue; - position = startPosition; - startAfterConnected = startPlaying; if (musicService != null) { - musicService.openQueue(MusicPlayerRemote.playingQueue, startPosition, startPlaying); + musicService.openAndPlayQueue(playingQueue, startPosition, startPlaying); } } @@ -123,25 +102,21 @@ public class MusicPlayerRemote { if (musicService != null) { return musicService.getCurrentSong(); } - try { - return getPlayingQueue().get(getPosition()); - } catch (Exception ignored) { - } return new Song(); } public static int getPosition() { if (musicService != null) { - position = musicService.getPosition(); + return musicService.getPosition(); } - return position; + return -1; } public static ArrayList getPlayingQueue() { if (musicService != null) { - playingQueue = musicService.getPlayingQueue(); + return musicService.getPlayingQueue(); } - return playingQueue; + return new ArrayList<>(); } public static int getSongProgressMillis() { @@ -168,26 +143,30 @@ public class MusicPlayerRemote { if (musicService != null) { return musicService.getRepeatMode(); } - return PreferenceManager.getDefaultSharedPreferences(context).getInt(AppKeys.SP_REPEAT_MODE, 0); + return MusicService.REPEAT_MODE_NONE; } public static int getShuffleMode() { if (musicService != null) { return musicService.getShuffleMode(); } - return PreferenceManager.getDefaultSharedPreferences(context).getInt(AppKeys.SP_SHUFFLE_MODE, 0); + return MusicService.SHUFFLE_MODE_NONE; } - public static void cycleRepeatMode() { + public static boolean cycleRepeatMode() { if (musicService != null) { musicService.cycleRepeatMode(); + return true; } + return false; } - public static void toggleShuffleMode() { + public static boolean toggleShuffleMode() { if (musicService != null) { musicService.toggleShuffle(); + return true; } + return false; } public static boolean setShuffleMode(final int shuffleMode) { @@ -198,103 +177,78 @@ public class MusicPlayerRemote { return false; } - public static void forceSetShuffleMode(final Context context, final int shuffleMode) { + public static boolean shuffleAllSongs(final Context context) { if (musicService != null) { - musicService.setShuffleMode(shuffleMode); - } else { - PreferenceManager.getDefaultSharedPreferences(context).edit() - .putInt(AppKeys.SP_SHUFFLE_MODE, shuffleMode) - .apply(); + ArrayList songs = SongLoader.getAllSongs(context); + if (!songs.isEmpty()) { + MusicPlayerRemote.openQueue(songs, new Random().nextInt(songs.size()), true); + setShuffleMode(MusicService.SHUFFLE_MODE_SHUFFLE); + } + return true; } + return false; } - public static void shuffleAllSongs(final Context context) { - ArrayList songs = SongLoader.getAllSongs(context); - if (!songs.isEmpty()) { - MusicPlayerRemote.openQueue(songs, new Random().nextInt(songs.size()), true); - forceSetShuffleMode(context, MusicService.SHUFFLE_MODE_SHUFFLE); - } - } - - public static void playNext(Song song) { + public static boolean playNext(Song song) { if (musicService != null) { musicService.addSong(getPosition() + 1, song); Toast.makeText(musicService, musicService.getResources().getString(R.string.added_title_to_playing_queue), Toast.LENGTH_SHORT).show(); + return true; } + return false; } - public static void enqueue(Song song) { + public static boolean enqueue(Song song) { if (musicService != null) { musicService.addSong(song); Toast.makeText(musicService, musicService.getResources().getString(R.string.added_title_to_playing_queue), Toast.LENGTH_SHORT).show(); + return true; } + return false; } - public static void enqueue(List songs) { + public static boolean enqueue(List songs) { if (musicService != null) { musicService.addSongs(songs); final String toast = songs.size() == 1 ? musicService.getResources().getString(R.string.added_title_to_playing_queue) : musicService.getResources().getString(R.string.added_x_titles_to_playing_queue, songs.size()); Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show(); + return true; } + return false; } - public static void removeFromQueue(Song song) { + public static boolean removeFromQueue(Song song) { if (musicService != null) { musicService.removeSong(song); + return true; } + return false; } - public static void removeFromQueue(int position) { + public static boolean removeFromQueue(int position) { if (musicService != null) { musicService.removeSong(position); + return true; } + return false; } - public static void moveSong(int from, int to) { + public static boolean moveSong(int from, int to) { if (musicService != null) { musicService.moveSong(from, to); + return true; } + return false; } public static int getAudioSessionId() { if (musicService != null) { return musicService.getAudioSessionId(); } - return AudioEffect.ERROR_BAD_VALUE; + return AudioEffect.ERROR_NO_INIT; } - @SuppressWarnings("unchecked") - public static void restorePreviousState() { - try { - ArrayList restoredQueue = (ArrayList) InternalStorageUtil.readObject(context, AppKeys.IS_PLAYING_QUEUE); - ArrayList restoredOriginalQueue = (ArrayList) InternalStorageUtil.readObject(context, AppKeys.IS_ORIGINAL_PLAYING_QUEUE); - int restoredPosition = (int) InternalStorageUtil.readObject(context, AppKeys.IS_POSITION_IN_QUEUE); - - if (musicService != null) { - musicService.restorePreviousState(restoredOriginalQueue, restoredQueue, restoredPosition); - } - - playingQueue = restoredQueue; - MusicPlayerRemote.restoredOriginalQueue = restoredOriginalQueue; - position = restoredPosition; - } catch (Exception e) { - Log.e(TAG, "error while restoring music service state", e); - playingQueue = new ArrayList<>(); - position = -1; - } - } - - public static void playFile(Uri uri) { -// if (musicService != null && uri != null) { -// String filename; -// String scheme = uri.getScheme(); -// if ("file".equals(scheme)) { -// filename = uri.getPath(); -// } else { -// filename = uri.toString(); -// } -// } + public static void playFile(String path) { //TODO - Toast.makeText(context, "Sorry, this feature is not available yet!", Toast.LENGTH_SHORT).show(); } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/service/MultiPlayer.java b/app/src/main/java/com/kabouzeid/gramophone/service/MultiPlayer.java index 6136f96f..c888ee59 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/service/MultiPlayer.java +++ b/app/src/main/java/com/kabouzeid/gramophone/service/MultiPlayer.java @@ -16,6 +16,9 @@ import com.kabouzeid.gramophone.util.PreferenceUtils; import java.io.IOException; import java.lang.ref.WeakReference; +/** + * @author Andrew Neal, Karim Abou Zeid (kabouzeid) + */ public class MultiPlayer implements MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener { public static final String TAG = MultiPlayer.class.getSimpleName(); @@ -41,13 +44,16 @@ public class MultiPlayer implements MediaPlayer.OnErrorListener, /** * @param path The path of the file, or the http/rtsp URL of the stream * you want to play + * @return True if the player has been prepared and is + * ready to play, false otherwise */ - public void setDataSource(final String path) { + public boolean setDataSource(final String path) { mIsInitialized = false; mIsInitialized = setDataSourceImpl(mCurrentMediaPlayer, path); if (mIsInitialized) { setNextDataSource(null); } + return mIsInitialized; } /** @@ -234,6 +240,10 @@ public class MultiPlayer implements MediaPlayer.OnErrorListener, */ @Override public boolean onError(final MediaPlayer mp, final int what, final int extra) { + mIsInitialized = false; + mCurrentMediaPlayer.release(); + mCurrentMediaPlayer = new MediaPlayer(); + mCurrentMediaPlayer.setWakeMode(mService.get(), PowerManager.PARTIAL_WAKE_LOCK); Toast.makeText(mService.get(), mService.get().getResources().getString(R.string.unplayable_file), Toast.LENGTH_SHORT).show(); return false; } diff --git a/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java b/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java index 75a0f1ad..b2b9b7b4 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java +++ b/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java @@ -48,6 +48,9 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; +/** + * @author Karim Abou Zeid (kabouzeid), Andrew Neal + */ public class MusicService extends Service { public static final String PHONOGRAPH_PACKAGE_NAME = "com.kabouzeid.gramophone"; public static final String MUSIC_PACKAGE_NAME = "com.android.music"; @@ -64,7 +67,9 @@ public class MusicService extends Service { public static final String PLAYSTATE_CHANGED = "com.kabouzeid.gramophone.playstatechanged"; public static final String REPEATMODE_CHANGED = "com.kabouzeid.gramophone.repeatmodechanged"; public static final String SHUFFLEMODE_CHANGED = "com.kabouzeid.gramophone.shufflemodechanged"; - public static final String POSITION_IN_SONG_CHANGED = "com.kabouzeid.phonograph.positionchanged"; + + public static final String SETTING_GAPLESS_PLAYBACK_CHANGED = "com.kabouzeid.gramophone.SETTING_GAPLESS_PLAYBACK_CHANGED"; + public static final String SETTING_GAPLESS_PLAYBACK_CHANGED_VALUE_EXTRA = "com.kabouzeid.gramophone.SETTING_GAPLESS_PLAYBACK_CHANGED_VALUE_EXTRA"; private static final int FOCUS_CHANGE = 5; private static final int DUCK = 6; @@ -93,11 +98,12 @@ public class MusicService extends Service { private int shuffleMode; private int repeatMode; private boolean pausedByTransientLossOfFocus; - private boolean thingsRegistered; + private boolean receiversAndRemoteControlClientRegistered; private boolean saveQueuesAgain; private boolean isSavingQueues; private PlayingNotificationHelper playingNotificationHelper; private AudioManager audioManager; + @SuppressWarnings("deprecation") private RemoteControlClient remoteControlClient; private PowerManager.WakeLock wakeLock; private String currentAlbumArtUri; @@ -108,13 +114,22 @@ public class MusicService extends Service { private final BroadcastReceiver becomingNoisyReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - if (intent.getAction().compareTo(AudioManager.ACTION_AUDIO_BECOMING_NOISY) == 0) { + if (intent.getAction().equals(AudioManager.ACTION_AUDIO_BECOMING_NOISY)) { pause(true); pause(false); } } }; + private final BroadcastReceiver gaplessPlaybackSettingChangedReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(SETTING_GAPLESS_PLAYBACK_CHANGED)) { + setGaplessPlaybackEnabled(intent.getBooleanExtra(SETTING_GAPLESS_PLAYBACK_CHANGED_VALUE_EXTRA, true)); + } + } + }; + private final AudioManager.OnAudioFocusChangeListener audioFocusListener = new AudioManager.OnAudioFocusChangeListener() { @Override public void onAudioFocusChange(final int focusChange) { @@ -127,6 +142,7 @@ public class MusicService extends Service { super.onCreate(); playingQueue = new ArrayList<>(); originalPlayingQueue = new ArrayList<>(); + playingNotificationHelper = new PlayingNotificationHelper(this); shuffleMode = PreferenceManager.getDefaultSharedPreferences(this).getInt(AppKeys.SP_SHUFFLE_MODE, 0); @@ -144,17 +160,19 @@ public class MusicService extends Service { player = new MultiPlayer(this); player.setHandler(playerHandler); - registerEverything(); + registerReceiversAndRemoteControlClient(); + + restoreQueueAndPosition(); } - private void registerEverything() { - if (!thingsRegistered) { - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY); - registerReceiver(becomingNoisyReceiver, intentFilter); + private void registerReceiversAndRemoteControlClient() { + if (!receiversAndRemoteControlClientRegistered) { + registerReceiver(becomingNoisyReceiver, new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY)); + registerReceiver(gaplessPlaybackSettingChangedReceiver, new IntentFilter(SETTING_GAPLESS_PLAYBACK_CHANGED)); + //noinspection deprecation getAudioManager().registerMediaButtonEventReceiver(new ComponentName(getApplicationContext(), MediaButtonIntentReceiver.class)); initRemoteControlClient(); - thingsRegistered = true; + receiversAndRemoteControlClientRegistered = true; } } @@ -165,6 +183,7 @@ public class MusicService extends Service { return audioManager; } + @SuppressWarnings("deprecation") private void initRemoteControlClient() { remoteControlClient = new RemoteControlClient(getMediaButtonIntent()); remoteControlClient.setTransportControlFlags( @@ -210,7 +229,7 @@ public class MusicService extends Service { stop(); break; case ACTION_QUIT: - killEverythingAndReleaseResources(); + saveAndQuit(); break; } } @@ -220,17 +239,9 @@ public class MusicService extends Service { @Override public void onDestroy() { - closeAudioEffectSession(); - unregisterEverything(); - - playerHandler.removeCallbacksAndMessages(null); - if (Build.VERSION.SDK_INT >= 18) { - handlerThread.quitSafely(); - } else { - handlerThread.quit(); - } - - killEverythingAndReleaseResources(); + saveAndQuit(); + releaseResources(); + wakeLock.release(); } @Override @@ -238,43 +249,51 @@ public class MusicService extends Service { return musicBind; } - @Override - public boolean onUnbind(Intent intent) { - unregisterEverything(); - killEverythingAndReleaseResources(); - return false; - } - - private void unregisterEverything() { - if (thingsRegistered) { + private void unregisterReceiversAndRemoteControlClient() { + if (receiversAndRemoteControlClientRegistered) { unregisterReceiver(becomingNoisyReceiver); + unregisterReceiver(gaplessPlaybackSettingChangedReceiver); + //noinspection deprecation getAudioManager().unregisterRemoteControlClient(remoteControlClient); + //noinspection deprecation getAudioManager().unregisterMediaButtonEventReceiver(new ComponentName(getApplicationContext(), MediaButtonIntentReceiver.class)); - getAudioManager().abandonAudioFocus(audioFocusListener); - thingsRegistered = false; + receiversAndRemoteControlClientRegistered = false; } } - private void killEverythingAndReleaseResources() { + private void saveAndQuit() { + unregisterReceiversAndRemoteControlClient(); + closeAudioEffectSession(); stop(); playingNotificationHelper.killNotification(); savePosition(); - saveQueues(); + saveQueuesImpl(); stopSelf(); } + private void releaseResources() { + playerHandler.removeCallbacksAndMessages(null); + if (Build.VERSION.SDK_INT >= 18) { + handlerThread.quitSafely(); + } else { + handlerThread.quit(); + } + player.release(); + player = null; + } + public void stop() { pausedByTransientLossOfFocus = false; player.stop(); - player.release(); notifyChange(PLAYSTATE_CHANGED); + getAudioManager().abandonAudioFocus(audioFocusListener); } public boolean isPlayingAndNotFadingDown() { return player.isPlaying() && !isFadingDown; } - public void saveQueues() { + public void saveQueuesImpl() { try { InternalStorageUtil.writeObject(MusicService.this, AppKeys.IS_PLAYING_QUEUE, playingQueue); InternalStorageUtil.writeObject(MusicService.this, AppKeys.IS_ORIGINAL_PLAYING_QUEUE, originalPlayingQueue); @@ -312,7 +331,7 @@ public class MusicService extends Service { synchronized (this) { setPosition(position); boolean prepared = openCurrent(); - prepareNext(); + if (prepared) prepareNext(); notifyChange(META_CHANGED); return prepared; } @@ -321,8 +340,7 @@ public class MusicService extends Service { private boolean openCurrent() { synchronized (this) { try { - player.setDataSource(getTrackUri(getCurrentSong())); - return true; + return player.setDataSource(getTrackUri(getCurrentSong())); } catch (Exception e) { return false; } @@ -389,6 +407,7 @@ public class MusicService extends Service { } private void updateRemoteControlClientBitmap(final Bitmap albumArt) { + //noinspection deprecation remoteControlClient .editMetadata(false) .putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, albumArt) @@ -473,7 +492,7 @@ public class MusicService extends Service { } } - public void openQueue(final ArrayList playingQueue, final int startPosition, final boolean startPlaying) { + public void openAndPlayQueue(final ArrayList playingQueue, final int startPosition, final boolean startPlaying) { if (playingQueue != null && !playingQueue.isEmpty() && startPosition >= 0 && startPosition < playingQueue.size()) { originalPlayingQueue = playingQueue; this.playingQueue = new ArrayList<>(originalPlayingQueue); @@ -505,7 +524,7 @@ public class MusicService extends Service { isSavingQueues = true; do { saveQueuesAgain = false; - saveQueues(); + saveQueuesImpl(); } while (saveQueuesAgain); isSavingQueues = false; } @@ -513,11 +532,21 @@ public class MusicService extends Service { } } - public void restorePreviousState(final ArrayList originalPlayingQueue, final ArrayList playingQueue, int position) { - this.originalPlayingQueue = originalPlayingQueue; - this.playingQueue = playingQueue; - this.position = position; - saveState(); + private void restoreQueueAndPosition() { + try { + @SuppressWarnings("unchecked") + ArrayList restoredQueue = (ArrayList) InternalStorageUtil.readObject(this, AppKeys.IS_PLAYING_QUEUE); + @SuppressWarnings("unchecked") + ArrayList restoredOriginalQueue = (ArrayList) InternalStorageUtil.readObject(this, AppKeys.IS_ORIGINAL_PLAYING_QUEUE); + int restoredPosition = (int) InternalStorageUtil.readObject(this, AppKeys.IS_POSITION_IN_QUEUE); + + this.originalPlayingQueue = restoredOriginalQueue; + this.playingQueue = restoredQueue; + + openTrackAndPrepareNextAt(restoredPosition); + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } } public void addSong(int position, Song song) { @@ -620,7 +649,10 @@ public class MusicService extends Service { playerHandler.removeMessages(FADE_DOWN_AND_PAUSE); playerHandler.sendEmptyMessage(FADE_UP_AND_RESUME); } else { - if (player != null) player.setVolume(1f); + try { + player.setVolume(1f); + } catch (IllegalStateException ignored) { + } playImpl(); } } @@ -633,6 +665,7 @@ public class MusicService extends Service { if (!player.isInitialized()) { playSongAt(getPosition()); } else { + registerReceiversAndRemoteControlClient(); player.start(); notifyChange(PLAYSTATE_CHANGED); } @@ -769,6 +802,7 @@ public class MusicService extends Service { final boolean isPlaying = isPlayingAndNotFadingDown(); playingNotificationHelper.updatePlayState(isPlaying); MusicPlayerWidget.updateWidgetsPlayState(this, isPlaying); + //noinspection deprecation remoteControlClient.setPlaybackState(isPlaying ? RemoteControlClient.PLAYSTATE_PLAYING : RemoteControlClient.PLAYSTATE_PAUSED); } else if (what.equals(META_CHANGED)) { updateNotification(); @@ -778,8 +812,6 @@ public class MusicService extends Service { } public int getAudioSessionId() { - if (player == null) - return AudioEffect.ERROR_BAD_VALUE; return player.getAudioSessionId(); } @@ -793,6 +825,14 @@ public class MusicService extends Service { wakeLock.acquire(milli); } + private void setGaplessPlaybackEnabled(boolean setEnabled) { + if (setEnabled) { + prepareNext(); + } else { + player.setNextDataSource(null); + } + } + public class MusicBinder extends Binder { public MusicService getService() { return MusicService.this; @@ -824,8 +864,7 @@ public class MusicService extends Service { } else { currentDuckVolume = .2f; } - if (service.player != null) - service.player.setVolume(currentDuckVolume); + service.player.setVolume(currentDuckVolume); break; case UNDUCK: @@ -835,8 +874,7 @@ public class MusicService extends Service { } else { currentDuckVolume = 1.0f; } - if (service.player != null) - service.player.setVolume(currentDuckVolume); + service.player.setVolume(currentDuckVolume); break; case FADE_DOWN_AND_PAUSE: @@ -852,8 +890,7 @@ public class MusicService extends Service { service.isFadingDown = false; service.pause(true); } - if (service.player != null) - service.player.setVolume(currentPlayPauseFadeVolume); + service.player.setVolume(currentPlayPauseFadeVolume); break; case FADE_UP_AND_RESUME: @@ -868,8 +905,10 @@ public class MusicService extends Service { } else { currentPlayPauseFadeVolume = 1.0f; } - if (service.player != null) + try { service.player.setVolume(currentPlayPauseFadeVolume); + } catch (IllegalStateException ignored) { + } break; case TRACK_WENT_TO_NEXT: @@ -893,7 +932,7 @@ public class MusicService extends Service { case FOCUS_CHANGE: switch (msg.arg1) { case AudioManager.AUDIOFOCUS_GAIN: - service.registerEverything(); + service.registerReceiversAndRemoteControlClient(); if (!service.isPlayingAndNotFadingDown() && service.pausedByTransientLossOfFocus) { service.play(false); } @@ -904,7 +943,7 @@ public class MusicService extends Service { case AudioManager.AUDIOFOCUS_LOSS: // Lost focus for an unbounded amount of time: stop playback and release media player service.pause(true); - service.unregisterEverything(); + service.unregisterReceiversAndRemoteControlClient(); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java index 94a25ebd..01ce81d5 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java @@ -248,11 +248,6 @@ public class MainActivity extends AbsFabActivity return TAG; } - @Override - protected void onResume() { - super.onResume(); - updateNavigationDrawerHeader(); - } private void updateNavigationDrawerHeader() { Song song = MusicPlayerRemote.getCurrentSong(); @@ -305,6 +300,12 @@ public class MainActivity extends AbsFabActivity updateNavigationDrawerHeader(); } + @Override + public void onServiceConnected() { + super.onServiceConnected(); + updateNavigationDrawerHeader(); + } + @Override public boolean onCreateOptionsMenu(Menu menu) { if (isAlbumPage()) { @@ -411,7 +412,7 @@ public class MainActivity extends AbsFabActivity MusicPlayerRemote.openQueue(SearchQueryHelper.getSongs(this, intent.getExtras()), 0, true); } if (uri != null && uri.toString().length() > 0) { - MusicPlayerRemote.playFile(uri); + MusicPlayerRemote.playFile(uri.toString()); handled = true; } else if (MediaStore.Audio.Playlists.CONTENT_TYPE.equals(mimeType)) { final int id = (int) parseIdFromIntent(intent, "playlistId", "playlist"); diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SettingsActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SettingsActivity.java index a19d89ba..67e5e561 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SettingsActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SettingsActivity.java @@ -20,6 +20,7 @@ import com.kabouzeid.gramophone.dialogs.ColorChooserDialog; import com.kabouzeid.gramophone.helper.PlayingNotificationHelper; import com.kabouzeid.gramophone.model.UIPreferenceChangedEvent; import com.kabouzeid.gramophone.prefs.ColorChooserPreference; +import com.kabouzeid.gramophone.service.MusicService; import com.kabouzeid.gramophone.ui.activities.base.AbsBaseActivity; import com.kabouzeid.gramophone.util.NavigationUtil; import com.kabouzeid.gramophone.util.PreferenceUtils; @@ -146,6 +147,15 @@ public class SettingsActivity extends AbsBaseActivity implements ColorChooserDia } }); + Preference gaplessPlayback = findPreference("gapless_playback"); + gaplessPlayback.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + getActivity().sendBroadcast(new Intent(MusicService.SETTING_GAPLESS_PLAYBACK_CHANGED).putExtra(MusicService.SETTING_GAPLESS_PLAYBACK_CHANGED_VALUE_EXTRA, (boolean) newValue)); + return true; + } + }); + equalizer = findPreference("equalizer"); resolveEqualizer(); equalizer.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsPlaybackStatusActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsPlaybackStatusActivity.java index f38fdecf..fa39747c 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsPlaybackStatusActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsPlaybackStatusActivity.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.service.MusicService; import java.lang.ref.WeakReference; @@ -13,7 +14,7 @@ import java.lang.ref.WeakReference; * @author Karim Abou Zeid (kabouzeid) */ public abstract class AbsPlaybackStatusActivity extends AbsBaseActivity { - private PlaybackStatus playbackStatus; + private PlaybackStatusReceiver playbackStatusReceiver; public void onPlayingMetaChanged() { @@ -31,35 +32,45 @@ public abstract class AbsPlaybackStatusActivity extends AbsBaseActivity { } + public void onServiceConnected() { + + } + @Override protected void onStart() { super.onStart(); - playbackStatus = new PlaybackStatus(this); + playbackStatusReceiver = new PlaybackStatusReceiver(this); + + // ensures that onServiceConnected() is called even if the service is already connected and wont sent the Intent again. + if (MusicPlayerRemote.isServiceConnected()) { + onServiceConnected(); + } final IntentFilter filter = new IntentFilter(); filter.addAction(MusicService.PLAYSTATE_CHANGED); filter.addAction(MusicService.SHUFFLEMODE_CHANGED); filter.addAction(MusicService.REPEATMODE_CHANGED); filter.addAction(MusicService.META_CHANGED); + filter.addAction(MusicPlayerRemote.SERVICE_BOUND); - registerReceiver(playbackStatus, filter); + registerReceiver(playbackStatusReceiver, filter); } @Override protected void onStop() { super.onStop(); try { - unregisterReceiver(playbackStatus); + unregisterReceiver(playbackStatusReceiver); } catch (Throwable ignored) { } } - private static final class PlaybackStatus extends BroadcastReceiver { + private static final class PlaybackStatusReceiver extends BroadcastReceiver { private final WeakReference reference; - public PlaybackStatus(final AbsPlaybackStatusActivity activity) { + public PlaybackStatusReceiver(final AbsPlaybackStatusActivity activity) { reference = new WeakReference<>(activity); } @@ -79,6 +90,9 @@ public abstract class AbsPlaybackStatusActivity extends AbsBaseActivity { case MusicService.SHUFFLEMODE_CHANGED: reference.get().onShuffleModeChanged(); break; + case MusicPlayerRemote.SERVICE_BOUND: + reference.get().onServiceConnected(); + break; } } }