Start of basic playback

This commit is contained in:
Eric Reed committed 2014-12-08 17:03:44 -05:00
1 parent 393ba2ca8d
commit 64e7f32714
7 files changed
+105 -52

No files matched your search

@@ -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();
}
}
});
@@ -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();
}
});
@@ -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<Movie> mItems = new ArrayList<Movie>();
private ArrayList<BaseItemDto> 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<Movie>();
mSelectedMovie = (Movie) getActivity()
.getIntent().getSerializableExtra(DetailsActivity.MOVIE);
mItems = new ArrayList<>();
mSelectedMovie = mApplication.getSerializer().DeserializeFromString(getActivity()
.getIntent().getStringExtra("BaseItemDto"), BaseItemDto.class);
List<Movie> 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<String, String>());
} 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);
@@ -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<ConnectionResult>() {
//connectionManager.Connect(response.getServers().get(0), new Response<ConnectionResult>() {
//force to dev server
connectionManager.Connect("eric-office:8096", new Response<ConnectionResult>() {
@Override
public void onResponse(ConnectionResult serverResult) {
switch (serverResult.getState()) {
case ServerSignIn:
try {
serverResult.getApiClient().AuthenticateUserAsync("Dad","124", new Response<AuthenticationResult>() {
serverResult.getApiClient().AuthenticateUserAsync("ebr","0101", new Response<AuthenticationResult>() {
@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);
@@ -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;
}
}
@@ -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);
@@ -3,7 +3,7 @@
<string name="app_name">MediaBrowserTv</string>
<string name="browse_title"><![CDATA[Videos by Your Company]]></string>
<string name="related_movies">Related Videos</string>
<string name="current_queue">Current Queue</string>
<string name="vertical_grid_title"><![CDATA[Vertical Video Grid]]></string>
<string name="error">Error</string>
<string name="ok">OK</string>