diff --git a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/BaseItemDetailsFragment.java b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/BaseItemDetailsFragment.java index 32720d9b6..65b556852 100644 --- a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/BaseItemDetailsFragment.java +++ b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/BaseItemDetailsFragment.java @@ -126,7 +126,8 @@ public class BaseItemDetailsFragment extends DetailsFragment { public void onActionClicked(Action action) { if (action.getId() == ACTION_PLAY) { Intent intent = new Intent(getActivity(), PlaybackOverlayActivity.class); - intent.putExtra("BaseItemDto", TvApp.getApplication().getSerializer().SerializeToString(mBaseItem)); + String[] items = new String[] {TvApp.getApplication().getSerializer().SerializeToString(mBaseItem)}; + intent.putExtra("Items", items); intent.putExtra(getResources().getString(R.string.should_start), true); startActivity(intent); } else { diff --git a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/PlaybackController.java b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/PlaybackController.java new file mode 100644 index 000000000..9cf83a64a --- /dev/null +++ b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/PlaybackController.java @@ -0,0 +1,131 @@ +package tv.mediabrowser.mediabrowsertv; + +import android.media.MediaPlayer; +import android.widget.VideoView; + +import java.util.List; + +import mediabrowser.model.dto.BaseItemDto; + +/** + * Created by Eric on 12/9/2014. + */ +public class PlaybackController { + List mItems; + VideoView mVideoView; + int mCurrentIndex = 0; + private int mCurrentPosition = 0; + private PlaybackState mPlaybackState = PlaybackState.IDLE; + private TvApp mApplication; + + + public PlaybackController(List items) { + mItems = items; + mApplication = TvApp.getApplication(); + + } + + public void init(VideoView view) { + mVideoView = view; + setupCallbacks(); + } + + public BaseItemDto getCurrentlyPlayingItem() { + return mItems.get(mCurrentIndex); + } + + /** + * Implementation of OnPlayPauseClickedListener + */ + public void onFragmentPlayPause(int position, Boolean playPause) { + Utils.Play(getCurrentlyPlayingItem(), mVideoView); + + if (position == 0 || mPlaybackState == PlaybackState.IDLE) { + setupCallbacks(); + mPlaybackState = PlaybackState.IDLE; + } + + if (playPause && mPlaybackState != PlaybackState.PLAYING) { + mPlaybackState = PlaybackState.PLAYING; + if (position > 0) { + mVideoView.seekTo(position); + mVideoView.start(); + } + } else { + mPlaybackState = PlaybackState.PAUSED; + mVideoView.pause(); + } + } + + public void play() { + + } + + public void next() { + + } + + public void prev() { + + } + + private void setupCallbacks() { + + mVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() { + + @Override + public boolean onError(MediaPlayer mp, int what, int extra) { + String msg = ""; + if (extra == MediaPlayer.MEDIA_ERROR_TIMED_OUT) { + msg = mApplication.getString(R.string.video_error_media_load_timeout); + } else if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) { + msg = mApplication.getString(R.string.video_error_server_inaccessible); + } else { + msg = mApplication.getString(R.string.video_error_unknown_error); + } + mVideoView.stopPlayback(); + mPlaybackState = PlaybackState.IDLE; + return false; + } + }); + + + mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + if (mPlaybackState == PlaybackState.PLAYING) { + mVideoView.start(); + } + } + }); + + + mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + mPlaybackState = PlaybackState.IDLE; + Long mbPos = (long) mVideoView.getCurrentPosition() * 10000; + Utils.Stop(TvApp.getApplication().getCurrentPlayingItem(), mbPos); + mVideoView.suspend(); + } + }); + + } + + public int getmCurrentPosition() { + return mCurrentPosition; + } + + public void setmCurrentPosition(int mCurrentPosition) { + this.mCurrentPosition = mCurrentPosition; + } + + + /* + * List of various states that we can be in + */ + public static enum PlaybackState { + PLAYING, PAUSED, BUFFERING, IDLE; + } + +} diff --git a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/PlaybackOverlayActivity.java b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/PlaybackOverlayActivity.java index 1a2227d00..b47635b58 100644 --- a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/PlaybackOverlayActivity.java +++ b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/PlaybackOverlayActivity.java @@ -14,26 +14,15 @@ package tv.mediabrowser.mediabrowsertv; import android.app.Activity; -import android.media.MediaPlayer; -import android.media.session.MediaController; import android.os.Bundle; import android.util.DisplayMetrics; -import android.util.Log; import android.widget.FrameLayout; import android.widget.VideoView; -import mediabrowser.apiinteraction.ApiClient; -import mediabrowser.apiinteraction.EmptyResponse; -import mediabrowser.model.dlna.StreamBuilder; -import mediabrowser.model.dlna.VideoOptions; -import mediabrowser.model.dto.BaseItemDto; -import mediabrowser.model.session.PlaybackStopInfo; - /** * PlaybackOverlayActivity for video playback that loads PlaybackOverlayFragment */ -public class PlaybackOverlayActivity extends Activity implements - PlaybackOverlayFragment.OnPlayPauseClickedListener { +public class PlaybackOverlayActivity extends Activity { private static final String TAG = "PlaybackOverlayActivity"; private static final double MEDIA_HEIGHT = 0.95; @@ -43,10 +32,8 @@ public class PlaybackOverlayActivity extends Activity implements private static final double MEDIA_BOTTOM_MARGIN = 0.025; private static final double MEDIA_LEFT_MARGIN = 0.025; - private ApiClient mApiClient; - private VideoView mVideoView; - private PlaybackState mPlaybackState = PlaybackState.IDLE; + private TvApp mApplication; /** * Called when the activity is first created. @@ -54,45 +41,22 @@ public class PlaybackOverlayActivity extends Activity implements @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mApiClient = TvApp.getApplication().getApiClient(); setContentView(R.layout.playback_controls); + mApplication = TvApp.getApplication(); loadViews(); - setupCallbacks(); //overScan(); } @Override public void onDestroy() { super.onDestroy(); - Utils.Stop(TvApp.getApplication().getCurrentPlayingItem(), mVideoView.getCurrentPosition()); mVideoView.suspend(); - } - - /** - * Implementation of OnPlayPauseClickedListener - */ - public void onFragmentPlayPause(BaseItemDto movie, int position, Boolean playPause) { - Utils.Play(movie, mVideoView); - - if (position == 0 || mPlaybackState == PlaybackState.IDLE) { - setupCallbacks(); - mPlaybackState = PlaybackState.IDLE; - } - - if (playPause && mPlaybackState != PlaybackState.PLAYING) { - mPlaybackState = PlaybackState.PLAYING; - if (position > 0) { - mVideoView.seekTo(position); - mVideoView.start(); - } - } else { - mPlaybackState = PlaybackState.PAUSED; - mVideoView.pause(); - } + Utils.Stop(mApplication.getPlaybackController().getCurrentlyPlayingItem(), mApplication.getPlaybackController().getmCurrentPosition() * 10000); } private void loadViews() { mVideoView = (VideoView) findViewById(R.id.videoView); + mApplication.getPlaybackController().init(mVideoView); } private void overScan() { @@ -108,55 +72,4 @@ public class PlaybackOverlayActivity extends Activity implements lp.setMargins(marginLeft, marginTop, marginRight, marginBottom); mVideoView.setLayoutParams(lp); } - - private void setupCallbacks() { - - mVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() { - - @Override - public boolean onError(MediaPlayer mp, int what, int extra) { - String msg = ""; - if (extra == MediaPlayer.MEDIA_ERROR_TIMED_OUT) { - msg = getString(R.string.video_error_media_load_timeout); - } else if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) { - msg = getString(R.string.video_error_server_inaccessible); - } else { - msg = getString(R.string.video_error_unknown_error); - } - mVideoView.stopPlayback(); - mPlaybackState = PlaybackState.IDLE; - return false; - } - }); - - - mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { - @Override - public void onPrepared(MediaPlayer mp) { - if (mPlaybackState == PlaybackState.PLAYING) { - mVideoView.start(); - } - } - }); - - - mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { - @Override - public void onCompletion(MediaPlayer mp) { - mPlaybackState = PlaybackState.IDLE; - Long mbPos = new Long(mVideoView.getCurrentPosition()) * 10000; - Utils.Stop(TvApp.getApplication().getCurrentPlayingItem(), mbPos); - mVideoView.suspend(); - } - }); - - } - - /* - * List of various states that we can be in - */ - public static enum PlaybackState { - PLAYING, PAUSED, BUFFERING, IDLE; - } - } diff --git a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/PlaybackOverlayFragment.java b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/PlaybackOverlayFragment.java index f25483e83..0c77d2f5b 100644 --- a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/PlaybackOverlayFragment.java +++ b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/PlaybackOverlayFragment.java @@ -18,8 +18,6 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.media.MediaMetadataRetriever; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter; @@ -49,15 +47,15 @@ import android.support.v17.leanback.widget.Row; import android.support.v17.leanback.widget.RowPresenter; import android.util.Log; import android.widget.Toast; +import android.widget.VideoView; import com.squareup.picasso.Picasso; import com.squareup.picasso.Target; -import java.net.URI; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; +import mediabrowser.apiinteraction.android.GsonJsonSerializer; import mediabrowser.model.dto.BaseItemDto; /* @@ -69,7 +67,6 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl private static Context sContext; private static final boolean SHOW_DETAIL = true; - private static final boolean HIDE_MORE_ACTIONS = false; private static final int PRIMARY_CONTROLS = 5; private static final boolean SHOW_IMAGE = PRIMARY_CONTROLS <= 5; private static final int BACKGROUND_TYPE = PlaybackOverlayFragment.BG_LIGHT; @@ -92,20 +89,13 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl private SkipNextAction mSkipNextAction; private SkipPreviousAction mSkipPreviousAction; private PlaybackControlsRow mPlaybackControlsRow; - private ArrayList mItems = new ArrayList<>(); - private int mCurrentItem; private Handler mHandler; private Runnable mRunnable; - private BaseItemDto mSelectedMovie; private TvApp mApplication; private PicassoPlaybackControlsRowTarget mPlaybackControlsRowTarget; - - OnPlayPauseClickedListener mCallback; - - // Container Activity must implement this interface - public interface OnPlayPauseClickedListener { - public void onFragmentPlayPause(BaseItemDto movie, int position, Boolean playPause); - } + private PlaybackController mPlaybackController; + private List mItemsToPlay = new ArrayList<>(); + private VideoView mVideoView; @Override public void onCreate(Bundle savedInstanceState) { @@ -114,15 +104,17 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl sContext = getActivity(); mApplication = TvApp.getApplication(); - mItems = new ArrayList<>(); - mSelectedMovie = mApplication.getSerializer().DeserializeFromString(getActivity() - .getIntent().getStringExtra("BaseItemDto"), BaseItemDto.class); + GsonJsonSerializer serializer = mApplication.getSerializer(); - //TODO get additional items to play from intent - mItems.add(mSelectedMovie); - mCurrentItem = 0; + String[] passedItems = getActivity().getIntent().getStringArrayExtra("Items"); + if (passedItems != null) { + for (String json : passedItems) { + mItemsToPlay.add((BaseItemDto) serializer.DeserializeFromString(json, BaseItemDto.class)); + } + } - //ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter()); + mApplication.setPlaybackController(new PlaybackController(mItemsToPlay)); + mPlaybackController = mApplication.getPlaybackController(); mHandler = new Handler(); @@ -147,23 +139,10 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl }); if (getActivity().getIntent().getBooleanExtra("ShouldStart", false)) { - mCallback.onFragmentPlayPause(mSelectedMovie, 0, true); + mPlaybackController.onFragmentPlayPause(0, true); } } - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - - // This makes sure that the container activity has implemented - // the callback interface. If not, it throws an exception - try { - mCallback = (OnPlayPauseClickedListener) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() - + " must implement OnPlayPauseClickedListener"); - } - } private void setupRows() { @@ -182,18 +161,16 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl if (mPlayPauseAction.getIndex() == PlayPauseAction.PLAY) { startProgressAutomation(); setFadingEnabled(true); - mCallback.onFragmentPlayPause(mItems.get(mCurrentItem), - mPlaybackControlsRow.getCurrentTime(), true); + mPlaybackController.onFragmentPlayPause(mPlaybackControlsRow.getCurrentTime(), true); } else { stopProgressAutomation(); setFadingEnabled(false); - mCallback.onFragmentPlayPause(mItems.get(mCurrentItem), - mPlaybackControlsRow.getCurrentTime(), false); + mPlaybackController.onFragmentPlayPause(mPlaybackControlsRow.getCurrentTime(), false); } } else if (action.getId() == mSkipNextAction.getId()) { - next(); + mPlaybackController.next(); } else if (action.getId() == mSkipPreviousAction.getId()) { - prev(); + mPlaybackController.prev(); } else if (action.getId() == mFastForwardAction.getId()) { Toast.makeText(getActivity(), "TODO: Fast Forward", Toast.LENGTH_SHORT).show(); } else if (action.getId() == mRewindAction.getId()) { @@ -205,20 +182,20 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl } } }); - playbackControlsRowPresenter.setSecondaryActionsHidden(HIDE_MORE_ACTIONS); + playbackControlsRowPresenter.setSecondaryActionsHidden(false); ps.addClassPresenter(PlaybackControlsRow.class, playbackControlsRowPresenter); ps.addClassPresenter(ListRow.class, new ListRowPresenter()); mRowsAdapter = new ArrayObjectAdapter(ps); addPlaybackControlsRow(); - if (mItems.size() > 1) addOtherRows(); // only show queue if more than one item + if (mItemsToPlay.size() > 1) addQueueRow(); // only show queue if more than one item setAdapter(mRowsAdapter); } private int getDuration() { - BaseItemDto movie = mItems.get(mCurrentItem); + BaseItemDto movie = mPlaybackController.getCurrentlyPlayingItem(); if (movie != null) { Long mbRuntime = movie.getRunTimeTicks(); @@ -230,13 +207,13 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl private void addPlaybackControlsRow() { if (SHOW_DETAIL) { - mPlaybackControlsRow = new PlaybackControlsRow(mSelectedMovie); + mPlaybackControlsRow = new PlaybackControlsRow(mPlaybackController.getCurrentlyPlayingItem()); } else { mPlaybackControlsRow = new PlaybackControlsRow(); } mRowsAdapter.add(mPlaybackControlsRow); - updatePlaybackRow(mCurrentItem); + updatePlaybackRow(); ControlButtonPresenterSelector presenterSelector = new ControlButtonPresenterSelector(); mPrimaryActionsAdapter = new ArrayObjectAdapter(presenterSelector); @@ -293,15 +270,10 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl } } - private void updatePlaybackRow(int index) { - if (mPlaybackControlsRow.getItem() != null) { - BaseItemDto item = (BaseItemDto) mPlaybackControlsRow.getItem(); -// item.setTitle(mItems.get(mCurrentItem).getTitle()); -// item.setStudio(mItems.get(mCurrentItem).getStudio()); - } + private void updatePlaybackRow() { if (SHOW_IMAGE) { mPlaybackControlsRowTarget = new PicassoPlaybackControlsRowTarget(mPlaybackControlsRow); - updateVideoImage(Utils.getPrimaryImageUrl(mItems.get(mCurrentItem), mApplication.getApiClient())); + updateVideoImage(Utils.getPrimaryImageUrl(mPlaybackController.getCurrentlyPlayingItem(), mApplication.getApiClient())); } mRowsAdapter.notifyArrayItemRangeChanged(0, 1); mPlaybackControlsRow.setTotalTime(getDuration()); @@ -309,9 +281,9 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl mPlaybackControlsRow.setBufferedProgress(0); } - private void addOtherRows() { + private void addQueueRow() { ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter()); - for (BaseItemDto movie : mItems) { + for (BaseItemDto movie : mItemsToPlay) { listRowAdapter.add(movie); } HeaderItem header = new HeaderItem(0, getString(R.string.current_queue), null); @@ -334,10 +306,11 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl int currentTime = mPlaybackControlsRow.getCurrentTime() + updatePeriod; int totalTime = mPlaybackControlsRow.getTotalTime(); mPlaybackControlsRow.setCurrentTime(currentTime); + mPlaybackController.setmCurrentPosition(currentTime); mPlaybackControlsRow.setBufferedProgress(currentTime + SIMULATED_BUFFERED_TIME); if (totalTime > 0 && totalTime <= currentTime) { - next(); + mPlaybackController.next(); } mHandler.postDelayed(this, updatePeriod); } @@ -345,30 +318,6 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl mHandler.postDelayed(mRunnable, getUpdatePeriod()); } - private void next() { - if (++mCurrentItem >= mItems.size()) { - mCurrentItem = 0; - } - - if (mPlayPauseAction.getIndex() == PlayPauseAction.PLAY) { - mCallback.onFragmentPlayPause(mItems.get(mCurrentItem), 0, false); - } else { - mCallback.onFragmentPlayPause(mItems.get(mCurrentItem), 0, true); - } - updatePlaybackRow(mCurrentItem); - } - - private void prev() { - if (--mCurrentItem < 0) { - mCurrentItem = mItems.size() - 1; - } - if (mPlayPauseAction.getIndex() == PlayPauseAction.PLAY) { - mCallback.onFragmentPlayPause(mItems.get(mCurrentItem), 0, false); - } else { - mCallback.onFragmentPlayPause(mItems.get(mCurrentItem), 0, true); - } - updatePlaybackRow(mCurrentItem); - } private void stopProgressAutomation() { if (mHandler != null && mRunnable != null) { diff --git a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/TvApp.java b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/TvApp.java index 0928452ec..e377fe534 100644 --- a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/TvApp.java +++ b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/TvApp.java @@ -24,6 +24,7 @@ public class TvApp extends Application { private static TvApp app; private UserDto currentUser; private BaseItemDto currentPlayingItem; + private PlaybackController playbackController; @Override public void onCreate() { @@ -93,4 +94,12 @@ public class TvApp extends Application { public void setCurrentPlayingItem(BaseItemDto currentPlayingItem) { this.currentPlayingItem = currentPlayingItem; } + + public PlaybackController getPlaybackController() { + return playbackController; + } + + public void setPlaybackController(PlaybackController playbackController) { + this.playbackController = playbackController; + } }