diff --git a/app/build.gradle b/app/build.gradle index 093d2720..5f92c85d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -27,8 +27,8 @@ android { applicationId "com.kabouzeid.gramophone" minSdkVersion 16 targetSdkVersion 22 - versionCode 33 - versionName "0.9.18b dev-1" + versionCode 35 + versionName "0.9.19b dev-1" } buildTypes { 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 eb506f61..26c382b8 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java +++ b/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java @@ -11,11 +11,9 @@ import android.preference.PreferenceManager; import android.util.Log; import android.widget.Toast; -import com.kabouzeid.gramophone.App; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.loader.SongLoader; import com.kabouzeid.gramophone.misc.AppKeys; -import com.kabouzeid.gramophone.model.MusicRemoteEvent; import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.service.MusicService; import com.kabouzeid.gramophone.util.InternalStorageUtil; @@ -46,13 +44,11 @@ public class MusicPlayerRemote { MusicService.MusicBinder binder = (MusicService.MusicBinder) service; musicService = binder.getService(); musicService.restorePreviousState(restoredOriginalQueue, playingQueue, position); - postToBus(MusicRemoteEvent.SERVICE_CONNECTED); } @Override public void onServiceDisconnected(ComponentName name) { musicService = null; - postToBus(MusicRemoteEvent.SERVICE_DISCONNECTED); } }; @@ -278,11 +274,6 @@ public class MusicPlayerRemote { } } - private static void postToBus(int event) { - MusicRemoteEvent musicRemoteEvent = new MusicRemoteEvent(event); - App.bus.post(musicRemoteEvent); - } - public static int getAudioSessionId() { if (musicService != null) { return musicService.getAudioSessionId(); @@ -304,8 +295,6 @@ public class MusicPlayerRemote { playingQueue = restoredQueue; MusicPlayerRemote.restoredOriginalQueue = restoredOriginalQueue; position = restoredPosition; - - postToBus(MusicRemoteEvent.STATE_RESTORED); } catch (Exception e) { Log.e(TAG, "error while restoring music service state", e); playingQueue = new ArrayList<>(); diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/MusicRemoteEvent.java b/app/src/main/java/com/kabouzeid/gramophone/model/MusicRemoteEvent.java deleted file mode 100644 index 782998c7..00000000 --- a/app/src/main/java/com/kabouzeid/gramophone/model/MusicRemoteEvent.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.kabouzeid.gramophone.model; - -/** - * @author Karim Abou Zeid (kabouzeid) - */ -public class MusicRemoteEvent { - public static final int PLAY = 0; - public static final int PAUSE = 1; - public static final int RESUME = 2; - public static final int STOP = 3; - public static final int NEXT = 4; - public static final int PREV = 5; - public static final int TRACK_CHANGED = 6; - - public static final int SONG_COMPLETED = 7; - public static final int QUEUE_COMPLETED = 8; - - public static final int SERVICE_CONNECTED = 9; - public static final int SERVICE_DISCONNECTED = 10; - - public static final int STATE_SAVED = 11; - public static final int STATE_RESTORED = 12; - - public static final int SHUFFLE_MODE_CHANGED = 13; - public static final int REPEAT_MODE_CHANGED = 14; - - private final int action; - - public MusicRemoteEvent(int action) { - this.action = action; - } - - public int getAction() { - return action; - } -} 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 53c92f6a..3bbb8c9d 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java +++ b/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java @@ -16,23 +16,26 @@ import android.media.RemoteControlClient; import android.media.audiofx.AudioEffect; import android.net.Uri; import android.os.Binder; +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.preference.PreferenceManager; import android.util.Log; import android.view.View; import android.widget.Toast; -import com.kabouzeid.gramophone.App; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.appwidget.MusicPlayerWidget; import com.kabouzeid.gramophone.helper.PlayingNotificationHelper; import com.kabouzeid.gramophone.helper.ShuffleHelper; import com.kabouzeid.gramophone.misc.AppKeys; -import com.kabouzeid.gramophone.model.MusicRemoteEvent; import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.util.InternalStorageUtil; import com.kabouzeid.gramophone.util.MusicUtil; +import com.kabouzeid.gramophone.util.PreferenceUtils; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.assist.ImageSize; @@ -41,10 +44,14 @@ import com.nostra13.universalimageloader.core.imageaware.NonViewAware; import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; import java.io.IOException; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; public class MusicService extends Service implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener, AudioManager.OnAudioFocusChangeListener { + public static final String PHONOGRAPH_PACKAGE_NAME = "com.kabouzeid.gramophone"; + public static final String MUSIC_PACKAGE_NAME = "com.android.music"; + public static final String ACTION_TOGGLE_PLAYBACK = "com.kabouzeid.gramophone.action.TOGGLE_PLAYBACK"; public static final String ACTION_PLAY = "com.kabouzeid.gramophone.action.PLAY"; public static final String ACTION_RESUME = "com.kabouzeid.gramophone.action.RESUME"; @@ -53,8 +60,18 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe public static final String ACTION_SKIP = "com.kabouzeid.gramophone.action.SKIP"; public static final String ACTION_REWIND = "com.kabouzeid.gramophone.action.REWIND"; public static final String ACTION_QUIT = "com.kabouzeid.gramophone.action.QUIT"; - public static final String META_CHANGED = "com.android.music.metachanged"; - public static final String PLAYSTATE_CHANGED = "com.android.music.playstatechanged"; + + public static final String META_CHANGED = "com.kabouzeid.gramophone.metachanged"; + 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"; + + private static final int FOCUSCHANGE = 5; + private static final int DUCK = 6; + private static final int UNDUCK = 7; + private static final int FADEDOWNANDPAUSE = 8; + private static final int FADEUPANDRESUME = 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; @@ -88,6 +105,9 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe private RemoteControlClient remoteControlClient; private PowerManager.WakeLock wakeLock; private String currentAlbumArtUri; + private MusicPlayerHandler playerHandler; + + private boolean fadingDown = false; public MusicService() { } @@ -107,6 +127,11 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName()); wakeLock.setReferenceCounted(false); + final HandlerThread thread = new HandlerThread("MusicPlayerHandler", + android.os.Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + playerHandler = new MusicPlayerHandler(this, thread.getLooper()); + registerEverything(); } @@ -226,20 +251,11 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe player.release(); player = null; } - playingNotificationHelper.updatePlayState(isPlaying()); - MusicPlayerWidget.updateWidgetsPlayState(this, isPlaying()); - remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED); - notifyOnMusicRemoteEventListeners(MusicRemoteEvent.STOP); notifyChange(PLAYSTATE_CHANGED); } public boolean isPlaying() { - return player != null && isPlayerPrepared && player.isPlaying(); - } - - private void notifyOnMusicRemoteEventListeners(int event) { - MusicRemoteEvent musicRemoteEvent = new MusicRemoteEvent(event); - App.bus.post(musicRemoteEvent); + return player != null && isPlayerPrepared && !fadingDown && player.isPlaying(); } public void saveQueues() { @@ -274,13 +290,7 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe @Override public void onCompletion(MediaPlayer mp) { - notifyOnMusicRemoteEventListeners(MusicRemoteEvent.SONG_COMPLETED); if (isLastTrack() && getRepeatMode() == REPEAT_MODE_NONE) { - notifyOnMusicRemoteEventListeners(MusicRemoteEvent.QUEUE_COMPLETED); - playingNotificationHelper.updatePlayState(isPlaying()); - MusicPlayerWidget.updateWidgetsPlayState(this, isPlaying()); - remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED); - notifyOnMusicRemoteEventListeners(MusicRemoteEvent.STOP); notifyChange(PLAYSTATE_CHANGED); } else { acquireWakeLock(30000); @@ -293,7 +303,6 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe if (isPlayerPrepared) { setPosition(getNextPosition(force)); playSong(); - notifyOnMusicRemoteEventListeners(MusicRemoteEvent.NEXT); } } } @@ -313,28 +322,17 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe } catch (Exception e) { player.reset(); player = null; - - notifyOnMusicRemoteEventListeners(MusicRemoteEvent.STOP); - playingNotificationHelper.updatePlayState(false); - MusicPlayerWidget.updateWidgetsPlayState(this, false); - remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED); notifyChange(PLAYSTATE_CHANGED); Toast.makeText(getApplicationContext(), getResources().getString(R.string.unplayable_file), Toast.LENGTH_SHORT).show(); return; } currentSongId = playingQueue.get(getPosition()).id; - updateNotification(); - updateWidgets(); - updateRemoteControlClient(); notifyChange(META_CHANGED); } else { - playingNotificationHelper.updatePlayState(false); - MusicPlayerWidget.updateWidgetsPlayState(this, false); notifyChange(PLAYSTATE_CHANGED); } } - notifyOnMusicRemoteEventListeners(MusicRemoteEvent.TRACK_CHANGED); } private void openAudioEffectSession() { @@ -467,7 +465,7 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe PreferenceManager.getDefaultSharedPreferences(this).edit() .putInt(AppKeys.SP_REPEAT_MODE, repeatMode) .apply(); - notifyOnMusicRemoteEventListeners(MusicRemoteEvent.REPEAT_MODE_CHANGED); + notifyChange(REPEATMODE_CHANGED); break; } } @@ -477,20 +475,15 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe isPlayerPrepared = false; player.reset(); player = null; - notifyOnMusicRemoteEventListeners(MusicRemoteEvent.STOP); + notifyChange(PLAYSTATE_CHANGED); return false; } @Override public void onPrepared(MediaPlayer mp) { - player.start(); isPlayerPrepared = true; openAudioEffectSession(); - playingNotificationHelper.updatePlayState(isPlaying()); - MusicPlayerWidget.updateWidgetsPlayState(this, isPlaying()); - remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING); - notifyOnMusicRemoteEventListeners(MusicRemoteEvent.PLAY); - notifyChange(PLAYSTATE_CHANGED); + resumePlaying(); savePosition(); releaseWakeLock(); } @@ -661,25 +654,38 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe } public void pausePlaying() { + if (PreferenceUtils.getInstance(this).fadePlayPauseAndInterruptions()) { + playerHandler.removeMessages(FADEUPANDRESUME); + playerHandler.sendEmptyMessage(FADEDOWNANDPAUSE); + } else { + pause(); + } + } + + private void pause() { + fadingDown = false; if (isPlaying()) { player.pause(); - playingNotificationHelper.updatePlayState(isPlaying()); - MusicPlayerWidget.updateWidgetsPlayState(this, isPlaying()); - remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PAUSED); - notifyOnMusicRemoteEventListeners(MusicRemoteEvent.PAUSE); notifyChange(PLAYSTATE_CHANGED); } } public void resumePlaying() { + if (PreferenceUtils.getInstance(this).fadePlayPauseAndInterruptions()) { + playerHandler.removeMessages(FADEDOWNANDPAUSE); + playerHandler.sendEmptyMessage(FADEUPANDRESUME); + } else { + player.setVolume(1f, 1f); + resume(); + } + } + + private void resume() { + fadingDown = false; if (!isPlaying()) { if (requestFocus()) { if (isPlayerPrepared()) { player.start(); - playingNotificationHelper.updatePlayState(isPlaying()); - MusicPlayerWidget.updateWidgetsPlayState(this, isPlaying()); - remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING); - notifyOnMusicRemoteEventListeners(MusicRemoteEvent.RESUME); notifyChange(PLAYSTATE_CHANGED); } else { playSong(); @@ -694,7 +700,6 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe if (position != -1) { setPosition(getPreviousPosition(force)); playSong(); - notifyOnMusicRemoteEventListeners(MusicRemoteEvent.PREV); } } @@ -788,7 +793,6 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe this.shuffleMode = shuffleMode; ShuffleHelper.makeShuffleList(this.playingQueue, getPosition()); setPosition(0); - notifyOnMusicRemoteEventListeners(MusicRemoteEvent.SHUFFLE_MODE_CHANGED); break; case SHUFFLE_MODE_NONE: this.shuffleMode = shuffleMode; @@ -800,24 +804,39 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe } } setPosition(newPosition); - notifyOnMusicRemoteEventListeners(MusicRemoteEvent.SHUFFLE_MODE_CHANGED); break; } + notifyChange(SHUFFLEMODE_CHANGED); } private void notifyChange(final String what) { - //to let other apps know whats playing. i.E. last.fm (scrobbling) or musixmatch - final Intent intent = new Intent(what); + final Intent internalIntent = new Intent(what); final int position = getPosition(); if (position >= 0 && !playingQueue.isEmpty()) { final Song currentSong = playingQueue.get(position); - intent.putExtra("id", currentSong.id); - intent.putExtra("artist", currentSong.artistName); - intent.putExtra("album", currentSong.albumName); - intent.putExtra("track", currentSong.title); + internalIntent.putExtra("id", currentSong.id); + internalIntent.putExtra("artist", currentSong.artistName); + internalIntent.putExtra("album", currentSong.albumName); + internalIntent.putExtra("track", currentSong.title); + } + internalIntent.putExtra("playing", isPlaying()); + sendStickyBroadcast(internalIntent); + + //to let other apps know whats playing. i.E. last.fm (scrobbling) or musixmatch + final Intent publicMusicIntent = new Intent(internalIntent); + publicMusicIntent.setAction(what.replace(PHONOGRAPH_PACKAGE_NAME, MUSIC_PACKAGE_NAME)); + sendStickyBroadcast(publicMusicIntent); + + if (what.equals(PLAYSTATE_CHANGED)) { + final boolean isPlaying = isPlaying(); + playingNotificationHelper.updatePlayState(isPlaying); + MusicPlayerWidget.updateWidgetsPlayState(this, isPlaying); + remoteControlClient.setPlaybackState(isPlaying ? RemoteControlClient.PLAYSTATE_PLAYING : RemoteControlClient.PLAYSTATE_PAUSED); + } else if (what.equals(META_CHANGED)) { + updateNotification(); + updateWidgets(); + updateRemoteControlClient(); } - intent.putExtra("playing", isPlaying()); - sendStickyBroadcast(intent); } public int getAudioSessionId() { @@ -841,4 +860,113 @@ public class MusicService extends Service implements MediaPlayer.OnPreparedListe return MusicService.this; } } + + private static final class MusicPlayerHandler extends Handler { + private final WeakReference mService; + private float currentDuckVolume = 1.0f; + private float currentPlayPauseFadeVolume = 1.0f; + + public MusicPlayerHandler(final MusicService service, final Looper looper) { + super(looper); + mService = new WeakReference<>(service); + } + + @Override + public void handleMessage(final Message msg) { + final MusicService service = mService.get(); + if (service == null) { + return; + } + + switch (msg.what) { + case DUCK: + currentDuckVolume -= .05f; + if (currentDuckVolume > .2f) { + sendEmptyMessageDelayed(DUCK, 10); + } else { + currentDuckVolume = .2f; + } + service.player.setVolume(currentDuckVolume, currentDuckVolume); + break; + + case UNDUCK: + currentDuckVolume += .05f; + if (currentDuckVolume < 1.0f) { + sendEmptyMessageDelayed(UNDUCK, 10); + } else { + currentDuckVolume = 1.0f; + } + service.player.setVolume(currentDuckVolume, currentDuckVolume); + break; + + case FADEDOWNANDPAUSE: + if (!service.fadingDown) { + service.fadingDown = true; + service.notifyChange(PLAYSTATE_CHANGED); + } + service.fadingDown = true; + currentPlayPauseFadeVolume -= .1f; + if (currentPlayPauseFadeVolume > 0f) { + sendEmptyMessageDelayed(FADEDOWNANDPAUSE, 10); + } else { + currentPlayPauseFadeVolume = 0f; + service.fadingDown = false; + service.pause(); + } + service.player.setVolume(currentPlayPauseFadeVolume, currentPlayPauseFadeVolume); + break; + + case FADEUPANDRESUME: + service.resume(); + currentPlayPauseFadeVolume += .1f; + if (currentPlayPauseFadeVolume < 1.0f) { + sendEmptyMessageDelayed(FADEUPANDRESUME, 10); + } else { + currentPlayPauseFadeVolume = 1.0f; + } + service.player.setVolume(currentPlayPauseFadeVolume, currentPlayPauseFadeVolume); + break; + + case FOCUSCHANGE: + switch (msg.arg1) { + case AudioManager.AUDIOFOCUS_GAIN: + if (!service.isPlaying()) { + if (service.wasPlayingBeforeFocusLoss) { + service.resumePlaying(); + service.wasPlayingBeforeFocusLoss = false; + } + } + removeMessages(DUCK); + sendEmptyMessage(UNDUCK); + break; + + case AudioManager.AUDIOFOCUS_LOSS: + // Lost focus for an unbounded amount of time: stop playback and release media player + service.wasPlayingBeforeFocusLoss = false; + service.pausePlaying(); + service.unregisterEverything(); + break; + + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: + // Lost focus for a short time, but we have to stop + // playback. We don't release the media player because playback + // is likely to resume + service.wasPlayingBeforeFocusLoss = service.isPlaying(); + service.pausePlaying(); + 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 + if (!service.isPlayerPrepared()) { + service.setUpMediaPlayerIfNeeded(); + } + removeMessages(UNDUCK); + sendEmptyMessage(DUCK); + break; + } + break; + } + } + } } 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 aff85bb4..70bea450 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 @@ -43,7 +43,6 @@ import com.kabouzeid.gramophone.interfaces.KabViewsDisableAble; import com.kabouzeid.gramophone.loader.AlbumSongLoader; import com.kabouzeid.gramophone.loader.ArtistSongLoader; import com.kabouzeid.gramophone.loader.PlaylistSongLoader; -import com.kabouzeid.gramophone.model.MusicRemoteEvent; import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.model.UIPreferenceChangedEvent; import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity; @@ -300,11 +299,9 @@ public class MainActivity extends AbsFabActivity } @Override - public void onMusicRemoteEvent(MusicRemoteEvent event) { - super.onMusicRemoteEvent(event); - if (event.getAction() == MusicRemoteEvent.STATE_RESTORED || event.getAction() == MusicRemoteEvent.TRACK_CHANGED) { - updateNavigationDrawerHeader(); - } + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateNavigationDrawerHeader(); } @Override diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java index cd21ce4d..13693056 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java @@ -37,7 +37,6 @@ import com.kabouzeid.gramophone.helper.bitmapblur.StackBlurManager; import com.kabouzeid.gramophone.loader.SongFilePathLoader; import com.kabouzeid.gramophone.misc.AppKeys; import com.kabouzeid.gramophone.misc.SmallTransitionListener; -import com.kabouzeid.gramophone.model.MusicRemoteEvent; import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.service.MusicService; import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity; @@ -469,19 +468,21 @@ public class MusicControllerActivity extends AbsFabActivity { } @Override - public void onMusicRemoteEvent(MusicRemoteEvent event) { - super.onMusicRemoteEvent(event); - switch (event.getAction()) { - case MusicRemoteEvent.TRACK_CHANGED: - updateCurrentSong(); - break; - case MusicRemoteEvent.REPEAT_MODE_CHANGED: - updateRepeatState(); - break; - case MusicRemoteEvent.SHUFFLE_MODE_CHANGED: - updateShuffleState(); - break; - } + public void onPlayingMetaChanged() { + super.onPlayingMetaChanged(); + updateCurrentSong(); + } + + @Override + public void onRepeatModeChanged() { + super.onRepeatModeChanged(); + updateRepeatState(); + } + + @Override + public void onShuffleModeChanged() { + super.onShuffleModeChanged(); + updateShuffleState(); } @Override diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsBaseActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsBaseActivity.java index 755bea24..c382bf5a 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsBaseActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsBaseActivity.java @@ -12,7 +12,7 @@ import com.squareup.otto.Subscribe; /** * @author Karim Abou Zeid (kabouzeid) */ -public abstract class AbsBaseActivity extends ThemeBaseActivity implements KabViewsDisableAble { +public abstract class AbsBaseActivity extends AbsThemeActivity implements KabViewsDisableAble { private App app; private boolean areViewsEnabled; diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsFabActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsFabActivity.java index 8ff515a9..2ff8ecd0 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsFabActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsFabActivity.java @@ -12,39 +12,28 @@ import android.view.View; import android.widget.Toast; import com.afollestad.materialdialogs.ThemeSingleton; -import com.kabouzeid.gramophone.App; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.misc.SmallOnGestureListener; -import com.kabouzeid.gramophone.model.MusicRemoteEvent; import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.util.NavigationUtil; import com.kabouzeid.gramophone.util.Util; import com.kabouzeid.gramophone.views.PlayPauseDrawable; -import com.squareup.otto.Subscribe; + +import hugo.weaving.DebugLog; /** * @author Karim Abou Zeid (kabouzeid) */ -public abstract class AbsFabActivity extends AbsBaseActivity { +public abstract class AbsFabActivity extends AbsPlaybackStatusActivity { public static final String TAG = AbsFabActivity.class.getSimpleName(); private FloatingActionButton fab; private PlayPauseDrawable playPauseDrawable; - private final Object busEventListener = new Object() { - @Subscribe - public void onBusEvent(MusicRemoteEvent event) { - onMusicRemoteEvent(event); - } - }; @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); - try { - App.bus.register(busEventListener); - } catch (Exception ignored) { - } setUpFab(); } @@ -116,6 +105,14 @@ public abstract class AbsFabActivity extends AbsBaseActivity { } } + protected void animateUpdateFabState() { + if (MusicPlayerRemote.isPlaying()) { + setFabPause(); + } else { + setFabPlay(); + } + } + protected FloatingActionButton getFab() { if (fab == null) { fab = (FloatingActionButton) findViewById(R.id.fab); @@ -145,33 +142,11 @@ public abstract class AbsFabActivity extends AbsBaseActivity { return sharedViewsWithFab; } + @DebugLog @Override - protected void onDestroy() { - super.onDestroy(); - try { - App.bus.unregister(busEventListener); - } catch (Exception ignored) { - } - } - - protected void onMusicRemoteEvent(MusicRemoteEvent event) { - switch (event.getAction()) { - case MusicRemoteEvent.PLAY: - setFabPause(); - break; - case MusicRemoteEvent.PAUSE: - setFabPlay(); - break; - case MusicRemoteEvent.RESUME: - setFabPause(); - break; - case MusicRemoteEvent.STOP: - setFabPlay(); - break; - case MusicRemoteEvent.QUEUE_COMPLETED: - setFabPlay(); - break; - } + public void onPlayStateChanged() { + super.onPlayStateChanged(); + animateUpdateFabState(); } private void setFabPlay() { @@ -181,8 +156,4 @@ public abstract class AbsFabActivity extends AbsBaseActivity { private void setFabPause() { playPauseDrawable.animatedPause(); } - - private void setFabColor() { - - } } 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 new file mode 100644 index 00000000..f38fdecf --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsPlaybackStatusActivity.java @@ -0,0 +1,85 @@ +package com.kabouzeid.gramophone.ui.activities.base; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import com.kabouzeid.gramophone.service.MusicService; + +import java.lang.ref.WeakReference; + +/** + * @author Karim Abou Zeid (kabouzeid) + */ +public abstract class AbsPlaybackStatusActivity extends AbsBaseActivity { + private PlaybackStatus playbackStatus; + + public void onPlayingMetaChanged() { + + } + + public void onPlayStateChanged() { + + } + + public void onRepeatModeChanged() { + + } + + public void onShuffleModeChanged() { + + } + + @Override + protected void onStart() { + super.onStart(); + + playbackStatus = new PlaybackStatus(this); + + 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); + + registerReceiver(playbackStatus, filter); + } + + @Override + protected void onStop() { + super.onStop(); + try { + unregisterReceiver(playbackStatus); + } catch (Throwable ignored) { + } + } + + private static final class PlaybackStatus extends BroadcastReceiver { + + private final WeakReference reference; + + public PlaybackStatus(final AbsPlaybackStatusActivity activity) { + reference = new WeakReference<>(activity); + } + + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + switch (action) { + case MusicService.META_CHANGED: + reference.get().onPlayingMetaChanged(); + break; + case MusicService.PLAYSTATE_CHANGED: + reference.get().onPlayStateChanged(); + break; + case MusicService.REPEATMODE_CHANGED: + reference.get().onRepeatModeChanged(); + break; + case MusicService.SHUFFLEMODE_CHANGED: + reference.get().onShuffleModeChanged(); + break; + } + } + } +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/ThemeBaseActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsThemeActivity.java similarity index 97% rename from app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/ThemeBaseActivity.java rename to app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsThemeActivity.java index e58d8f36..10fadd1f 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/ThemeBaseActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsThemeActivity.java @@ -16,7 +16,7 @@ import com.kabouzeid.gramophone.util.Util; * @author Aidan Follestad (afollestad), Karim Abou Zeid (kabouzeid) */ -public abstract class ThemeBaseActivity extends AppCompatActivity implements KabViewsDisableAble { +public abstract class AbsThemeActivity extends AppCompatActivity implements KabViewsDisableAble { private int colorPrimary; private int colorPrimaryDarker; private int colorAccent; diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtils.java b/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtils.java index ddec7935..57aeb9df 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtils.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtils.java @@ -40,6 +40,7 @@ public final class PreferenceUtils { public static final String LARGER_TITLE_BOX_NOW_PLAYING = "larger_title_box_now_playing"; public static final String ALTERNATIVE_PROGRESS_SLIDER_NOW_PLAYING = "alternative_progress_slider_now_playing"; public static final String PLAYBACK_CONTROLLER_CARD_NOW_PLAYING = "playback_controller_card_now_playing"; + public static final String FADE_PLAY_PAUSE = "fade_play_pause"; private static PreferenceUtils sInstance; @@ -187,6 +188,10 @@ public final class PreferenceUtils { return mPreferences.getBoolean(ALTERNATIVE_PROGRESS_SLIDER_NOW_PLAYING, false); } + public final boolean fadePlayPauseAndInterruptions() { + return mPreferences.getBoolean(FADE_PLAY_PAUSE, true); + } + // public final boolean downloadMissingArtistImages() { // return mPreferences.getBoolean(DOWNLOAD_MISSING_ARTIST_IMAGES, true); // } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5ea30c3f..54117509 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -107,6 +107,7 @@ Tag editor Everywhere else Colored album footers + Fade play/pause Force square album art Opaque toolbar Opaque statusbar @@ -139,6 +140,7 @@ Song "Only available on Lollipop." "Album footers in the grid are colored with the album cover\'s palette." + "Fades the song in/out on play/pause." Album art in the now playing view is forced to be squared. The toolbar is opaque and do not cover the album art. The statusbar is opaque and do not cover the album art. diff --git a/app/src/main/res/xml/pref_audio.xml b/app/src/main/res/xml/pref_audio.xml index 0be7b2a6..9b0b089f 100644 --- a/app/src/main/res/xml/pref_audio.xml +++ b/app/src/main/res/xml/pref_audio.xml @@ -3,6 +3,14 @@ + +