/app/src/main/java/com/vpaliy/melophile/playback/PlaybackManager.java

https://github.com/vpaliyX/Melophile · Java · 272 lines · 224 code · 46 blank · 2 comment · 24 complexity · 07054577e8366851da828ca9fe7ff540 MD5 · raw file

  1. package com.vpaliy.melophile.playback;
  2. import android.os.Bundle;
  3. import android.os.SystemClock;
  4. import android.support.v4.media.MediaMetadataCompat;
  5. import android.support.v4.media.session.MediaSessionCompat;
  6. import android.support.v4.media.session.PlaybackStateCompat;
  7. import com.vpaliy.data.mapper.Mapper;
  8. import com.vpaliy.domain.interactor.SaveInteractor;
  9. import com.vpaliy.domain.model.Track;
  10. import com.vpaliy.domain.playback.Playback;
  11. import com.vpaliy.domain.playback.QueueManager;
  12. import java.util.concurrent.TimeUnit;
  13. import javax.inject.Inject;
  14. import com.vpaliy.domain.playback.PlayerScope;
  15. @SuppressWarnings("WeakerAccess")
  16. @PlayerScope
  17. public class PlaybackManager implements Playback.Callback {
  18. private static final String TAG = PlaybackManager.class.getSimpleName();
  19. private PlaybackServiceCallback serviceCallback;
  20. private MediaSessionCallback mediaSessionCallback;
  21. private Mapper<MediaMetadataCompat, Track> mapper;
  22. private MetadataUpdateListener updateListener;
  23. private QueueManager queueManager;
  24. private Playback playback;
  25. private SaveInteractor saveInteractor;
  26. private boolean isRepeat;
  27. private boolean isShuffle;
  28. private int lastState;
  29. @Inject
  30. public PlaybackManager(Playback playback, Mapper<MediaMetadataCompat, Track> mapper, SaveInteractor saveInteractor) {
  31. this.mediaSessionCallback = new MediaSessionCallback();
  32. this.playback = playback;
  33. this.playback.setCallback(this);
  34. this.mapper = mapper;
  35. this.saveInteractor = saveInteractor;
  36. }
  37. public void setUpdateListener(MetadataUpdateListener updateListener) {
  38. this.updateListener = updateListener;
  39. }
  40. public MediaSessionCallback getMediaSessionCallback() {
  41. return mediaSessionCallback;
  42. }
  43. public void setQueueManager(QueueManager queueManager) {
  44. this.queueManager = queueManager;
  45. }
  46. public void handlePlayRequest(Track track) {
  47. if (track != null) {
  48. saveInteractor.saveTrack(track);
  49. playback.play(track.getStreamUrl());
  50. updateMetadata();
  51. }
  52. }
  53. public Playback getPlayback() {
  54. return playback;
  55. }
  56. private long getAvailableActions() {
  57. long actions =
  58. PlaybackStateCompat.ACTION_PLAY_PAUSE |
  59. PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID |
  60. PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH |
  61. PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS |
  62. PlaybackStateCompat.ACTION_SKIP_TO_NEXT;
  63. if (playback.isPlaying()) {
  64. actions |= PlaybackStateCompat.ACTION_PAUSE;
  65. } else {
  66. actions |= PlaybackStateCompat.ACTION_PLAY;
  67. }
  68. //
  69. if (isRepeat) {
  70. actions |= PlaybackStateCompat.ACTION_SET_REPEAT_MODE;
  71. }
  72. //
  73. if (isShuffle) {
  74. actions |= PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE_ENABLED;
  75. }
  76. return actions;
  77. }
  78. public void handlePauseRequest() {
  79. playback.pause();
  80. }
  81. public void handleStopRequest() {
  82. if (!playback.isPlaying()) {
  83. playback.stop();
  84. }
  85. }
  86. @Override
  87. public void onPlay() {
  88. updatePlaybackState(PlaybackStateCompat.STATE_PLAYING);
  89. serviceCallback.onPlaybackStart();
  90. }
  91. @Override
  92. public void onStop() {
  93. updatePlaybackState(PlaybackStateCompat.STATE_STOPPED);
  94. serviceCallback.onPlaybackStop();
  95. }
  96. @Override
  97. public void onError() {
  98. updateListener.onMetadataRetrieveError();
  99. }
  100. @Override
  101. public void onCompletetion() {
  102. Track track = isRepeat ? queueManager.current() : queueManager.next();
  103. if (isRepeat) {
  104. playback.invalidateCurrent();
  105. }
  106. handlePlayRequest(track);
  107. }
  108. public void handleResumeRequest() {
  109. if (queueManager != null) {
  110. handlePlayRequest(queueManager.current());
  111. }
  112. }
  113. public void handleNextRequest() {
  114. if (queueManager != null) {
  115. playback.invalidateCurrent();
  116. handlePlayRequest(queueManager.next());
  117. }
  118. }
  119. public void handlePrevRequest() {
  120. if (queueManager != null) {
  121. long position = TimeUnit.MILLISECONDS.toSeconds(playback.getPosition());
  122. playback.invalidateCurrent();
  123. if (position > 5 || position <= 2) {
  124. handlePlayRequest(queueManager.previous());
  125. } else {
  126. handlePlayRequest(queueManager.current());
  127. }
  128. }
  129. }
  130. private void handleRepeatMode() {
  131. isRepeat = !isRepeat;
  132. updatePlaybackState(lastState);
  133. }
  134. private void handleShuffleMode() {
  135. isShuffle = !isShuffle;
  136. if (queueManager != null) {
  137. queueManager.shuffle();
  138. }
  139. updatePlaybackState(lastState);
  140. }
  141. @Override
  142. public void onPause() {
  143. updatePlaybackState(PlaybackStateCompat.STATE_PAUSED);
  144. serviceCallback.onPlaybackStop();
  145. }
  146. public void updatePlaybackState(int state) {
  147. long position = playback.getPosition();
  148. this.lastState = state;
  149. if (state == PlaybackStateCompat.STATE_PLAYING ||
  150. state == PlaybackStateCompat.STATE_PAUSED) {
  151. serviceCallback.onNotificationRequired();
  152. }
  153. PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder()
  154. .setActions(getAvailableActions())
  155. .setState(state, position, 1.0f, SystemClock.elapsedRealtime());
  156. serviceCallback.onPlaybackStateUpdated(builder.build());
  157. }
  158. private void updateMetadata() {
  159. if (updateListener != null) {
  160. MediaMetadataCompat result = new MediaMetadataCompat.Builder(mapper.map(queueManager.current()))
  161. .putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, queueManager.size())
  162. .putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, queueManager.currentIndex() + 1)
  163. .putLong(MediaMetadataCompat.METADATA_KEY_DISC_NUMBER, playback.getPosition())
  164. .build();
  165. updateListener.onMetadataChanged(result);
  166. }
  167. }
  168. public void setServiceCallback(PlaybackServiceCallback serviceCallback) {
  169. this.serviceCallback = serviceCallback;
  170. }
  171. private class MediaSessionCallback extends MediaSessionCompat.Callback {
  172. @Override
  173. public void onPlay() {
  174. super.onPlay();
  175. handlePlayRequest(queueManager.current());
  176. }
  177. @Override
  178. public void onSkipToNext() {
  179. super.onSkipToNext();
  180. handleNextRequest();
  181. }
  182. @Override
  183. public void onSkipToPrevious() {
  184. super.onSkipToPrevious();
  185. handlePrevRequest();
  186. }
  187. @Override
  188. public void onPause() {
  189. super.onPause();
  190. handlePauseRequest();
  191. }
  192. @Override
  193. public void onSetRepeatMode(int repeatMode) {
  194. handleRepeatMode();
  195. }
  196. @Override
  197. public void onSetShuffleModeEnabled(boolean enabled) {
  198. super.onSetShuffleModeEnabled(enabled);
  199. handleShuffleMode();
  200. }
  201. @Override
  202. public void onStop() {
  203. super.onStop();
  204. handleStopRequest();
  205. }
  206. @Override
  207. public void onSeekTo(long pos) {
  208. super.onSeekTo(pos);
  209. playback.seekTo((int) pos);
  210. }
  211. @Override
  212. public void onCustomAction(String action, Bundle extras) {
  213. super.onCustomAction(action, extras);
  214. }
  215. }
  216. public interface MetadataUpdateListener {
  217. void onMetadataChanged(MediaMetadataCompat metadata);
  218. void onMetadataRetrieveError();
  219. }
  220. public interface PlaybackServiceCallback {
  221. void onPlaybackStart();
  222. void onPlaybackStop();
  223. void onNotificationRequired();
  224. void onPlaybackStateUpdated(PlaybackStateCompat newState);
  225. }
  226. }