/* * Copyright 2016 Substance Mobile * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.animbus.music.media; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.support.v4.media.session.MediaControllerCompat.TransportControls; import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.PlaybackStateCompat; import android.util.Log; import android.widget.Toast; import com.animbus.music.R; import com.animbus.music.media.objects.Album; import com.animbus.music.media.objects.Song; import com.animbus.music.media.stable.PlaybackManager; import com.animbus.music.media.stable.QueueManager; import com.animbus.music.media.stable.ServiceHelper; import com.animbus.music.util.Options; import java.util.ArrayList; import java.util.List; import static com.animbus.music.media.MediaService.ACTION_START; import static com.animbus.music.media.MediaService.LocalPlayback; import static com.animbus.music.media.MediaService.PlaybackBase; /** * Created by Adrian on 11/14/2015. */ public class PlaybackRemote { private static final String TAG = "PlaybackRemote"; static volatile TransportControls remote; private static volatile Context mContext; private static volatile MediaService mService; static volatile List<Song> mQueue = new ArrayList<>(); static volatile int mCurrentSongPos = 0; static volatile List<Song> tempSongList; static volatile int tempListStartPos; static volatile boolean tempRepeating; static volatile PlaybackBase tempIMPL; static volatile boolean tempNotifyListener; static volatile Song tempSong; static volatile Uri tempUri; static volatile int tempCommand = -1; public static final PlaybackBase LOCAL = new LocalPlayback(); private PlaybackRemote() { } // This is separate from init because the context needs to be set at the very beginning. init is called // when the service starts, and the only way to start the service is by using a context. // the service is started right before the media request is called, so the remote variable will be initialised and // can be used because it is set when init is called, when the service starts. public static void setUp(Context context) { mContext = context; ServiceHelper.get(context).initService(); } public static void init(MediaService service) { mService = service; remote = service.mSession.getController().getTransportControls(); if (tempIMPL != null) { service.inject(tempIMPL); tempIMPL = null; } if (tempCommand == 0) { play(tempUri); } else if (tempCommand == 1) { play(tempSong); } else if (tempCommand == 2) { play(tempSongList, tempListStartPos); } tempUri = null; tempSong = null; tempSongList = null; tempListStartPos = -1; tempCommand = -1; } public static void inject(PlaybackBase impl) { if (mService != null) mService.inject(impl); else tempIMPL = impl; } public static boolean startServiceIfNecessary() { if (mService == null) mContext.startService(new Intent(ACTION_START).setClass(mContext, MediaService.class)); return mService == null; } /////////////////////////////////////////////////////////////////////////// // Here go all of the controls /////////////////////////////////////////////////////////////////////////// public static void play(Uri uri) { if (Options.useStableService()) { Toast.makeText(mContext, R.string.msg_coming_soon, Toast.LENGTH_SHORT).show(); return; } if (!startServiceIfNecessary()) remote.playFromUri(uri, null); else { tempCommand = 0; tempUri = uri; } } public static void play(Song song) { if (Options.useStableService()) { PlaybackManager.get().play(song); return; } if (!startServiceIfNecessary()) remote.playFromMediaId(String.valueOf(song.getID()), null); else { tempCommand = 1; tempSong = song; } } public static void play(List<Song> songs, int startPos) { if (Options.useStableService()) { PlaybackManager.get().play(songs, startPos); return; } tempSongList = songs; tempListStartPos = startPos; if (!startServiceIfNecessary()) remote.sendCustomAction(PlaybackBase.ACTION_PLAY_FROM_LIST, null); else tempCommand = 2; } public static void playQueueItem(int pos) { if (Options.useStableService()) { PlaybackManager.get().playQueueItem(pos); return; } play(getQueue().get(pos)); setCurrentSongPos(pos); } public static void resume() { if (Options.useStableService()) { PlaybackManager.get().resume(); return; } remote.play(); } public static void pause() { if (Options.useStableService()) { PlaybackManager.get().pause(); return; } remote.pause(); } public static void next() { if (Options.useStableService()) { PlaybackManager.get().playNext(); return; } remote.skipToNext(); } public static void prev() { if (Options.useStableService()) { PlaybackManager.get().playPrev(true); return; } remote.skipToPrevious(); } public static void toggleRepeat() { if (Options.useStableService()) { PlaybackManager.get().setRepeat(!PlaybackManager.get().isLooping()); return; } setRepeat(!mService.IMPL.isRepeating()); } public static void setRepeat(boolean repeating) { if (Options.useStableService()) { PlaybackManager.get().setRepeat(repeating); return; } remote.sendCustomAction(PlaybackBase.ACTION_SET_REPEAT, null); tempRepeating = repeating; } public static boolean isRepeating() { if (Options.useStableService()) { return PlaybackManager.get().isLooping(); } return mService.IMPL.isRepeating(); } public static void seek(long time) { if (Options.useStableService()) { PlaybackManager.get().seekTo((int)time); return; } remote.seekTo(time); } public static void stop() { if (Options.useStableService()) { PlaybackManager.get().stop(); return; } remote.stop(); killService(); } public static void killService() { mService.stopSelf(); } /////////////////////////////////////////////////////////////////////////// // All of the queue things /////////////////////////////////////////////////////////////////////////// public static List<Song> getQueue() { if (Options.useStableService()) { return QueueManager.get().getCurrentQueueAsSong(); } return mQueue; } public static void setQueue(List<Song> queue) { if (Options.useStableService()) { QueueManager.get().setQueueAsSongList(queue); return; } mQueue = queue; } public static void addToQueue(Song s) { if (Options.useStableService()) { QueueManager.get().addToQueue(s); return; } mQueue.add(s); } public static void setCurrentSongPos(int currentSongPos) { if (Options.useStableService()) { QueueManager.get().setCurrentSongPos(currentSongPos); return; } mCurrentSongPos = currentSongPos; } public static int getCurrentSongPos() { if (Options.useStableService()) { return QueueManager.get().getCurrentSongPos(); } return mCurrentSongPos; } public static Song getCurrentSong() { if (Options.useStableService()) { return PlaybackManager.get().getCurrentSong(); } if (!getQueue().isEmpty()) return getQueue().get(getCurrentSongPos()); return null; } public static int getNextSongPos() { if (Options.useStableService()) { return QueueManager.get().updateNextSongPos(); } int pos; pos = mCurrentSongPos + 1; if (pos > (mQueue.size() - 1)) { pos = 0; } setCurrentSongPos(pos); return pos; } public static int getPrevSongPos() { if (Options.useStableService()) { return QueueManager.get().updatePrevSongPos(); } int pos; pos = mCurrentSongPos - 1; if (pos == 0) { pos = (mQueue.size() - 1); } setCurrentSongPos(pos); return pos; } /////////////////////////////////////////////////////////////////////////// // All of the other tidbits /////////////////////////////////////////////////////////////////////////// public static MediaSessionCompat.Token getToken() { if (Options.useStableService()) { return PlaybackManager.get().getService().getSession().getSessionToken(); } return mService.mSession.getSessionToken(); } public static PlaybackStateCompat getState() { if (Options.useStableService()) { return PlaybackManager.get().getService().getStateObj(); } return mService.mState; } public static MediaSessionCompat getSession() { if (Options.useStableService()) { return PlaybackManager.get().getService().getSession(); } return mService.mSession; } public static boolean isActive() { if (Options.useStableService()) { return PlaybackManager.get().isActive(); } return mService != null && mService.mSession.isActive(); } public static boolean isPlaying() { if (Options.useStableService()) { return PlaybackManager.get().isPlaying(); } return mService.IMPL.isPlaying(); } public static int getCurrentPosInSong() { if (Options.useStableService()) { return PlaybackManager.get().getCurrentPosInSong(); } return mService.IMPL.getCurrentPosInSong(); } ////////////////////////////////////////////////////////////////////////// // Listener /////////////////////////////////////////////////////////////////////////// static ArrayList<SongChangedListener> songListeners = new ArrayList<>(); static ArrayList<StateChangedListener> stateListeners = new ArrayList<>(); static { PlaybackManager.get().registerListener(new PlaybackManager.OnChangedListener() { @Override public void onSongChanged(Song song) { updateSongListeners(song); } @Override public void onPlaybackStateChanged(PlaybackStateCompat state) { updateStateListeners(state); } }); } public interface SongChangedListener { void onSongChanged(Song newSong); } public interface StateChangedListener { void onStateChanged(PlaybackStateCompat newState); } public static void registerSongListener(SongChangedListener listener) { if (!songListeners.contains(listener)) songListeners.add(listener); else Log.d(TAG, "This listener is already registered"); } public static void registerStateListener(StateChangedListener listener) { if (!stateListeners.contains(listener)) stateListeners.add(listener); else Log.d(TAG, "This listener is already registered"); } protected static void updateSongListeners(Song newSong) { for (SongChangedListener l : songListeners) l.onSongChanged(newSong); } protected static void updateSongListeners(Uri uri) { if (Options.useStableService()) { Toast.makeText(mContext, R.string.msg_coming_soon, Toast.LENGTH_SHORT).show(); return; } Song s = Library.findSongByUri(uri); if (s == null) { //Builds the song s = new Song(); Album a = new Album(); s.setTitle(mContext.getString(R.string.title_uri)); s.setSongArtist(mContext.getString(R.string.artist_uri)); a.setContext(mContext); updateSongListeners(s); } //Sets the queue to this one song List<Song> newQueue = new ArrayList<>(); newQueue.add(s); setQueue(newQueue); setCurrentSongPos(0); } protected static void updateStateListeners(PlaybackStateCompat newState) { for (StateChangedListener l : stateListeners) l.onStateChanged(newState); } }