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 be21e10da..32720d9b6 100644 --- a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/BaseItemDetailsFragment.java +++ b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/BaseItemDetailsFragment.java @@ -1,8 +1,6 @@ package tv.mediabrowser.mediabrowsertv; import java.io.IOException; -import java.util.Collections; -import java.util.List; import android.content.Intent; import android.graphics.Bitmap; @@ -16,7 +14,6 @@ import android.support.v17.leanback.widget.ArrayObjectAdapter; import android.support.v17.leanback.widget.ClassPresenterSelector; import android.support.v17.leanback.widget.DetailsOverviewRow; import android.support.v17.leanback.widget.DetailsOverviewRowPresenter; -import android.support.v17.leanback.widget.HeaderItem; import android.support.v17.leanback.widget.ImageCardView; import android.support.v17.leanback.widget.ListRow; import android.support.v17.leanback.widget.ListRowPresenter; @@ -40,7 +37,7 @@ import mediabrowser.model.dto.BaseItemDto; public class BaseItemDetailsFragment extends DetailsFragment { private static final String TAG = "BaseItemDetailsFragment"; - private static final int ACTION_WATCH_TRAILER = 1; + private static final int ACTION_PLAY = 1; private static final int ACTION_RENT = 2; private static final int ACTION_BUY = 3; @@ -110,8 +107,7 @@ public class BaseItemDetailsFragment extends DetailsFragment { } catch (IOException e) { } - row.addAction(new Action(ACTION_WATCH_TRAILER, getResources().getString( - R.string.watch_trailer_1), getResources().getString(R.string.watch_trailer_2))); + row.addAction(new Action(ACTION_PLAY, "Play", "From Beginning")); row.addAction(new Action(ACTION_RENT, getResources().getString(R.string.rent_1), getResources().getString(R.string.rent_2))); row.addAction(new Action(ACTION_BUY, getResources().getString(R.string.buy_1), @@ -128,13 +124,13 @@ public class BaseItemDetailsFragment extends DetailsFragment { mDorPresenter.setOnActionClickedListener(new OnActionClickedListener() { @Override public void onActionClicked(Action action) { - if (action.getId() == ACTION_WATCH_TRAILER) { + if (action.getId() == ACTION_PLAY) { Intent intent = new Intent(getActivity(), PlaybackOverlayActivity.class); intent.putExtra("BaseItemDto", TvApp.getApplication().getSerializer().SerializeToString(mBaseItem)); intent.putExtra(getResources().getString(R.string.should_start), true); startActivity(intent); } else { - Toast.makeText(getActivity(), action.toString(), Toast.LENGTH_SHORT).show(); + Toast.makeText(getActivity(), action.toString() + " not implemented", Toast.LENGTH_SHORT).show(); } } }); 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 d047a7f8f..2559fa16c 100644 --- a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/PlaybackOverlayActivity.java +++ b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/PlaybackOverlayActivity.java @@ -15,12 +15,20 @@ 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 */ @@ -35,6 +43,7 @@ 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; @@ -45,23 +54,25 @@ public class PlaybackOverlayActivity extends Activity implements @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mApiClient = TvApp.getApplication().getApiClient(); setContentView(R.layout.playback_controls); loadViews(); - //setupCallbacks(); - overScan(); + setupCallbacks(); + //overScan(); } @Override public void onDestroy() { super.onDestroy(); + Utils.Stop(TvApp.getApplication().getCurrentPlayingItem(), mVideoView.getCurrentPosition()); mVideoView.suspend(); } /** * Implementation of OnPlayPauseClickedListener */ - public void onFragmentPlayPause(Movie movie, int position, Boolean playPause) { - mVideoView.setVideoPath(movie.getVideoUrl()); + public void onFragmentPlayPause(BaseItemDto movie, int position, Boolean playPause) { + Utils.Play(movie, mVideoView); if (position == 0 || mPlaybackState == PlaybackState.IDLE) { setupCallbacks(); @@ -133,6 +144,8 @@ public class PlaybackOverlayActivity extends Activity implements @Override public void onCompletion(MediaPlayer mp) { mPlaybackState = PlaybackState.IDLE; + Utils.Stop(TvApp.getApplication().getCurrentPlayingItem(), mVideoView.getCurrentPosition()); + mVideoView.suspend(); } }); 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 af5b3a558..76a61badf 100644 --- a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/PlaybackOverlayFragment.java +++ b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/PlaybackOverlayFragment.java @@ -58,6 +58,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import mediabrowser.model.dto.BaseItemDto; + /* * Class for video playback with media control */ @@ -90,18 +92,19 @@ 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 ArrayList mItems = new ArrayList<>(); private int mCurrentItem; private Handler mHandler; private Runnable mRunnable; - private Movie mSelectedMovie; + private BaseItemDto mSelectedMovie; + private TvApp mApplication; private PicassoPlaybackControlsRowTarget mPlaybackControlsRowTarget; OnPlayPauseClickedListener mCallback; // Container Activity must implement this interface public interface OnPlayPauseClickedListener { - public void onFragmentPlayPause(Movie movie, int position, Boolean playPause); + public void onFragmentPlayPause(BaseItemDto movie, int position, Boolean playPause); } @Override @@ -109,21 +112,17 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl Log.i(TAG, "onCreate"); super.onCreate(savedInstanceState); sContext = getActivity(); + mApplication = TvApp.getApplication(); - mItems = new ArrayList(); - mSelectedMovie = (Movie) getActivity() - .getIntent().getSerializableExtra(DetailsActivity.MOVIE); + mItems = new ArrayList<>(); + mSelectedMovie = mApplication.getSerializer().DeserializeFromString(getActivity() + .getIntent().getStringExtra("BaseItemDto"), BaseItemDto.class); - List movies = MovieList.list; + //TODO get additional items to play from intent + mItems.add(mSelectedMovie); + mCurrentItem = 0; - ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter()); - - for (int j = 0; j < movies.size(); j++) { - mItems.add(movies.get(j)); - if (mSelectedMovie.getTitle().contentEquals(movies.get(j).getTitle())) { - mCurrentItem = j; - } - } + //ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter()); mHandler = new Handler(); @@ -146,6 +145,10 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl Log.i(TAG, "onItemClicked: " + item + " row " + row); } }); + + if (getActivity().getIntent().getBooleanExtra("ShouldStart", false)) { + mCallback.onFragmentPlayPause(mSelectedMovie, 0, true); + } } @Override @@ -215,16 +218,8 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl } private int getDuration() { - Movie movie = mItems.get(mCurrentItem); - MediaMetadataRetriever mmr = new MediaMetadataRetriever(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - mmr.setDataSource(movie.getVideoUrl(), new HashMap()); - } else { - mmr.setDataSource(movie.getVideoUrl()); - } - String time = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); - long duration = Long.parseLong(time); - return (int) duration; + BaseItemDto movie = mItems.get(mCurrentItem); + return movie != null ? movie.getRunTimeTicks().intValue() : 0; } private void addPlaybackControlsRow() { @@ -294,13 +289,13 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl private void updatePlaybackRow(int index) { if (mPlaybackControlsRow.getItem() != null) { - Movie item = (Movie) mPlaybackControlsRow.getItem(); - item.setTitle(mItems.get(mCurrentItem).getTitle()); - item.setStudio(mItems.get(mCurrentItem).getStudio()); + BaseItemDto item = (BaseItemDto) mPlaybackControlsRow.getItem(); +// item.setTitle(mItems.get(mCurrentItem).getTitle()); +// item.setStudio(mItems.get(mCurrentItem).getStudio()); } if (SHOW_IMAGE) { mPlaybackControlsRowTarget = new PicassoPlaybackControlsRowTarget(mPlaybackControlsRow); - updateVideoImage(mItems.get(mCurrentItem).getCardImageURI()); + updateVideoImage(Utils.getPrimaryImageUrl(mItems.get(mCurrentItem), mApplication.getApiClient())); } mRowsAdapter.notifyArrayItemRangeChanged(0, 1); mPlaybackControlsRow.setTotalTime(getDuration()); @@ -310,10 +305,10 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl private void addOtherRows() { ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter()); - for (Movie movie : mItems) { + for (BaseItemDto movie : mItems) { listRowAdapter.add(movie); } - HeaderItem header = new HeaderItem(0, getString(R.string.related_movies), null); + HeaderItem header = new HeaderItem(0, getString(R.string.current_queue), null); mRowsAdapter.add(new ListRow(header, listRowAdapter)); } @@ -384,8 +379,9 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl static class DescriptionPresenter extends AbstractDetailsDescriptionPresenter { @Override protected void onBindDescription(ViewHolder viewHolder, Object item) { - viewHolder.getTitle().setText(((Movie) item).getTitle()); - viewHolder.getSubtitle().setText(((Movie) item).getStudio()); + BaseItemDto movie = (BaseItemDto) item; + viewHolder.getTitle().setText(movie.getName()); + viewHolder.getSubtitle().setText(movie.getOfficialRating()); } } @@ -413,9 +409,9 @@ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.Pl } } - protected void updateVideoImage(URI uri) { + protected void updateVideoImage(String url) { Picasso.with(sContext) - .load(uri.toString()) + .load(url) .resize(Utils.convertDpToPixel(sContext, CARD_WIDTH), Utils.convertDpToPixel(sContext, CARD_HEIGHT)) .into(mPlaybackControlsRowTarget); diff --git a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/StartupActivity.java b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/StartupActivity.java index ac1dedee4..f2a2bf826 100644 --- a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/StartupActivity.java +++ b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/StartupActivity.java @@ -81,16 +81,18 @@ public class StartupActivity extends Activity { break; case ServerSignIn: logger.Debug("Sign in with server "+ response.getServers().get(0).getName() + " total: " + response.getServers().size()); - connectionManager.Connect(response.getServers().get(0), new Response() { + //connectionManager.Connect(response.getServers().get(0), new Response() { + //force to dev server + connectionManager.Connect("eric-office:8096", new Response() { @Override public void onResponse(ConnectionResult serverResult) { switch (serverResult.getState()) { case ServerSignIn: try { - serverResult.getApiClient().AuthenticateUserAsync("Dad","124", new Response() { + serverResult.getApiClient().AuthenticateUserAsync("ebr","0101", new Response() { @Override public void onResponse(AuthenticationResult authenticationResult) { - logger.Debug("Signed in as Dad."); + logger.Debug("Signed in as " + authenticationResult.getUser().getName()); application.setCurrentUser(authenticationResult.getUser()); Intent intent = new Intent(activity, MainActivity.class); startActivity(intent); 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 4a1ffef09..9ec259197 100644 --- a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/TvApp.java +++ b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/TvApp.java @@ -7,6 +7,7 @@ import mediabrowser.apiinteraction.ApiClient; import mediabrowser.apiinteraction.IConnectionManager; import mediabrowser.apiinteraction.android.GsonJsonSerializer; import mediabrowser.logging.ConsoleLogger; +import mediabrowser.model.dto.BaseItemDto; import mediabrowser.model.dto.UserDto; import mediabrowser.model.logging.ILogger; import mediabrowser.model.serialization.IJsonSerializer; @@ -21,6 +22,7 @@ public class TvApp extends Application { private GsonJsonSerializer serializer; private static TvApp app; private UserDto currentUser; + private BaseItemDto currentPlayingItem; @Override public void onCreate() { @@ -77,4 +79,12 @@ public class TvApp extends Application { public ApiClient getApiClient() { return connectionManager.GetApiClient(currentUser); } + + public BaseItemDto getCurrentPlayingItem() { + return currentPlayingItem; + } + + public void setCurrentPlayingItem(BaseItemDto currentPlayingItem) { + this.currentPlayingItem = currentPlayingItem; + } } diff --git a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/Utils.java b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/Utils.java index aaef069f8..fface7a20 100644 --- a/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/Utils.java +++ b/MediaBrowserTv/app/src/main/java/tv/mediabrowser/mediabrowsertv/Utils.java @@ -9,13 +9,21 @@ import android.media.ToneGenerator; import android.view.Display; import android.view.WindowManager; import android.widget.Toast; +import android.widget.VideoView; import java.net.URI; import mediabrowser.apiinteraction.ApiClient; +import mediabrowser.apiinteraction.EmptyResponse; +import mediabrowser.model.dlna.StreamBuilder; +import mediabrowser.model.dlna.StreamInfo; +import mediabrowser.model.dlna.VideoOptions; +import mediabrowser.model.dlna.profiles.AndroidProfile; import mediabrowser.model.dto.BaseItemDto; import mediabrowser.model.dto.ImageOptions; import mediabrowser.model.entities.ImageType; +import mediabrowser.model.session.PlaybackStartInfo; +import mediabrowser.model.session.PlaybackStopInfo; /** * A collection of utility methods, all static. @@ -135,7 +143,7 @@ public class Utils { public static String getPrimaryImageUrl(BaseItemDto item, ApiClient apiClient) { ImageOptions options = new ImageOptions(); - options.setMaxWidth(320); + options.setMaxWidth(500); options.setImageType(ImageType.Primary); options.setTag(item.getImageTags().get(ImageType.Primary)); @@ -172,6 +180,34 @@ public class Utils { } } + public static void Play(BaseItemDto item, VideoView view) { + StreamBuilder builder = new StreamBuilder(); + VideoOptions options = new VideoOptions(); + ApiClient apiClient = TvApp.getApplication().getApiClient(); + options.setDeviceId(apiClient.getDeviceId()); + options.setItemId(item.getId()); + options.setMediaSources(item.getMediaSources()); + options.setProfile(new AndroidProfile()); + StreamInfo info = builder.BuildVideoItem(options); + view.setVideoPath(info.ToUrl(apiClient.getApiUrl())); + TvApp.getApplication().setCurrentPlayingItem(item); + + PlaybackStartInfo startInfo = new PlaybackStartInfo(); + startInfo.setItemId(item.getId()); + apiClient.ReportPlaybackStartAsync(startInfo, new EmptyResponse()); + + } + + public static void Stop(BaseItemDto item, long pos) { + PlaybackStopInfo info = new PlaybackStopInfo(); + ApiClient apiClient = TvApp.getApplication().getApiClient(); + info.setItemId(item.getId()); + info.setPositionTicks(pos); + apiClient.ReportPlaybackStoppedAsync(info, new EmptyResponse()); + apiClient.StopTranscodingProcesses(apiClient.getDeviceId(), new EmptyResponse()); + + } + public static void Beep() { // send the tone to the "alarm" stream (classic beeps go there) with 50% volume ToneGenerator toneG = new ToneGenerator(AudioManager.STREAM_ALARM, 50); diff --git a/MediaBrowserTv/app/src/main/res/values/strings.xml b/MediaBrowserTv/app/src/main/res/values/strings.xml index d51493901..1e955bd66 100644 --- a/MediaBrowserTv/app/src/main/res/values/strings.xml +++ b/MediaBrowserTv/app/src/main/res/values/strings.xml @@ -3,7 +3,7 @@ MediaBrowserTv - Related Videos + Current Queue Error OK