add all the generated example code

This commit is contained in:
Felix 2017-03-18 00:32:28 +01:00
parent 7b9c724e10
commit 2df7c3fb94
73 changed files with 1584 additions and 0 deletions

View file

@ -0,0 +1,33 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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 de.nicidienase.chaosflix;
import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter;
import de.nicidienase.chaosflix.entities.Movie;
public class DetailsDescriptionPresenter extends AbstractDetailsDescriptionPresenter {
@Override
protected void onBindDescription(ViewHolder viewHolder, Object item) {
Movie movie = (Movie) item;
if (movie != null) {
viewHolder.getTitle().setText(movie.getTitle());
viewHolder.getSubtitle().setText(movie.getStudio());
viewHolder.getBody().setText(movie.getDescription());
}
}
}

View file

@ -0,0 +1,91 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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 de.nicidienase.chaosflix;
import android.content.Context;
import android.graphics.Point;
import android.view.Display;
import android.view.WindowManager;
import android.widget.Toast;
/**
* A collection of utility methods, all static.
*/
public class Utils {
/*
* Making sure public utility methods remain static
*/
private Utils() {
}
/**
* Returns the screen/display size
*/
public static Point getDisplaySize(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size;
}
/**
* Shows a (long) toast
*/
public static void showToast(Context context, String msg) {
Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
}
/**
* Shows a (long) toast.
*/
public static void showToast(Context context, int resourceId) {
Toast.makeText(context, context.getString(resourceId), Toast.LENGTH_LONG).show();
}
public static int convertDpToPixel(Context ctx, int dp) {
float density = ctx.getResources().getDisplayMetrics().density;
return Math.round((float) dp * density);
}
/**
* Formats time in milliseconds to hh:mm:ss string format.
*/
public static String formatMillis(int millis) {
String result = "";
int hr = millis / 3600000;
millis %= 3600000;
int min = millis / 60000;
millis %= 60000;
int sec = millis / 1000;
if (hr > 0) {
result += hr + ":";
}
if (min >= 0) {
if (min > 9) {
result += min + ":";
} else {
result += "0" + min + ":";
}
}
if (sec > 9) {
result += sec;
} else {
result += "0" + sec;
}
return result;
}
}

View file

@ -0,0 +1,82 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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 de.nicidienase.chaosflix.activities;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.os.Handler;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import de.nicidienase.chaosflix.fragments.ErrorFragment;
import de.nicidienase.chaosflix.R;
/*
* BrowseErrorActivity shows how to use ErrorFragment
*/
public class BrowseErrorActivity extends Activity {
private static int TIMER_DELAY = 3000;
private static int SPINNER_WIDTH = 100;
private static int SPINNER_HEIGHT = 100;
private ErrorFragment mErrorFragment;
private SpinnerFragment mSpinnerFragment;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testError();
}
private void testError() {
mErrorFragment = new ErrorFragment();
getFragmentManager().beginTransaction().add(R.id.main_browse_fragment, mErrorFragment).commit();
mSpinnerFragment = new SpinnerFragment();
getFragmentManager().beginTransaction().add(R.id.main_browse_fragment, mSpinnerFragment).commit();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
getFragmentManager().beginTransaction().remove(mSpinnerFragment).commit();
mErrorFragment.setErrorContent();
}
}, TIMER_DELAY);
}
static public class SpinnerFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ProgressBar progressBar = new ProgressBar(container.getContext());
if (container instanceof FrameLayout) {
FrameLayout.LayoutParams layoutParams =
new FrameLayout.LayoutParams(SPINNER_WIDTH, SPINNER_HEIGHT, Gravity.CENTER);
progressBar.setLayoutParams(layoutParams);
}
return progressBar;
}
}
}

View file

@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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 de.nicidienase.chaosflix.activities;
import android.app.Activity;
import android.os.Bundle;
import de.nicidienase.chaosflix.R;
/*
* Details activity class that loads LeanbackDetailsFragment class
*/
public class DetailsActivity extends Activity {
public static final String SHARED_ELEMENT_NAME = "hero";
public static final String MOVIE = "Movie";
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details);
}
}

View file

@ -0,0 +1,257 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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 de.nicidienase.chaosflix.activities;
import android.app.Activity;
import android.graphics.Bitmap;
import android.media.MediaMetadata;
import android.media.MediaPlayer;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.net.Uri;
import android.os.Bundle;
import android.view.KeyEvent;
import android.widget.VideoView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import de.nicidienase.chaosflix.R;
import de.nicidienase.chaosflix.entities.Movie;
import de.nicidienase.chaosflix.fragments.PlaybackOverlayFragment;
/**
* PlaybackOverlayActivity for video playback that loads PlaybackOverlayFragment
*/
public class PlaybackOverlayActivity extends Activity implements
PlaybackOverlayFragment.OnPlayPauseClickedListener {
private static final String TAG = "PlaybackOverlayActivity";
private VideoView mVideoView;
private LeanbackPlaybackState mPlaybackState = LeanbackPlaybackState.IDLE;
private MediaSession mSession;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.playback_controls);
loadViews();
setupCallbacks();
mSession = new MediaSession(this, "LeanbackSampleApp");
mSession.setCallback(new MediaSessionCallback());
mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
mSession.setActive(true);
}
@Override
public void onDestroy() {
super.onDestroy();
mVideoView.suspend();
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
PlaybackOverlayFragment playbackOverlayFragment = (PlaybackOverlayFragment) getFragmentManager().findFragmentById(R.id.playback_controls_fragment);
switch (keyCode) {
case KeyEvent.KEYCODE_MEDIA_PLAY:
playbackOverlayFragment.togglePlayback(false);
return true;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
playbackOverlayFragment.togglePlayback(false);
return true;
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
if (mPlaybackState == LeanbackPlaybackState.PLAYING) {
playbackOverlayFragment.togglePlayback(false);
} else {
playbackOverlayFragment.togglePlayback(true);
}
return true;
default:
return super.onKeyUp(keyCode, event);
}
}
/**
* Implementation of OnPlayPauseClickedListener
*/
public void onFragmentPlayPause(Movie movie, int position, Boolean playPause) {
mVideoView.setVideoPath(movie.getVideoUrl());
if (position == 0 || mPlaybackState == LeanbackPlaybackState.IDLE) {
setupCallbacks();
mPlaybackState = LeanbackPlaybackState.IDLE;
}
if (playPause && mPlaybackState != LeanbackPlaybackState.PLAYING) {
mPlaybackState = LeanbackPlaybackState.PLAYING;
if (position > 0) {
mVideoView.seekTo(position);
mVideoView.start();
}
} else {
mPlaybackState = LeanbackPlaybackState.PAUSED;
mVideoView.pause();
}
updatePlaybackState(position);
updateMetadata(movie);
}
private void updatePlaybackState(int position) {
PlaybackState.Builder stateBuilder = new PlaybackState.Builder()
.setActions(getAvailableActions());
int state = PlaybackState.STATE_PLAYING;
if (mPlaybackState == LeanbackPlaybackState.PAUSED) {
state = PlaybackState.STATE_PAUSED;
}
stateBuilder.setState(state, position, 1.0f);
mSession.setPlaybackState(stateBuilder.build());
}
private long getAvailableActions() {
long actions = PlaybackState.ACTION_PLAY |
PlaybackState.ACTION_PLAY_FROM_MEDIA_ID |
PlaybackState.ACTION_PLAY_FROM_SEARCH;
if (mPlaybackState == LeanbackPlaybackState.PLAYING) {
actions |= PlaybackState.ACTION_PAUSE;
}
return actions;
}
private void updateMetadata(final Movie movie) {
final MediaMetadata.Builder metadataBuilder = new MediaMetadata.Builder();
String title = movie.getTitle().replace("_", " -");
metadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE, title);
metadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE,
movie.getDescription());
metadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI,
movie.getCardImageUrl());
// And at minimum the title and artist for legacy support
metadataBuilder.putString(MediaMetadata.METADATA_KEY_TITLE, title);
metadataBuilder.putString(MediaMetadata.METADATA_KEY_ARTIST, movie.getStudio());
Glide.with(this)
.load(Uri.parse(movie.getCardImageUrl()))
.asBitmap()
.into(new SimpleTarget<Bitmap>(500, 500) {
@Override
public void onResourceReady(Bitmap bitmap, GlideAnimation anim) {
metadataBuilder.putBitmap(MediaMetadata.METADATA_KEY_ART, bitmap);
mSession.setMetadata(metadataBuilder.build());
}
});
}
private void loadViews() {
mVideoView = (VideoView) findViewById(R.id.videoView);
mVideoView.setFocusable(false);
mVideoView.setFocusableInTouchMode(false);
}
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 = LeanbackPlaybackState.IDLE;
return false;
}
});
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
if (mPlaybackState == LeanbackPlaybackState.PLAYING) {
mVideoView.start();
}
}
});
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mPlaybackState = LeanbackPlaybackState.IDLE;
}
});
}
@Override
public void onResume() {
super.onResume();
mSession.setActive(true);
}
@Override
public void onPause() {
super.onPause();
if (mVideoView.isPlaying()) {
if (!requestVisibleBehind(true)) {
// Try to play behind launcher, but if it fails, stop playback.
stopPlayback();
}
} else {
requestVisibleBehind(false);
}
}
@Override
protected void onStop() {
super.onStop();
mSession.release();
}
@Override
public void onVisibleBehindCanceled() {
super.onVisibleBehindCanceled();
}
private void stopPlayback() {
if (mVideoView != null) {
mVideoView.stopPlayback();
}
}
/*
* List of various states that we can be in
*/
public enum LeanbackPlaybackState {
PLAYING, PAUSED, BUFFERING, IDLE
}
private class MediaSessionCallback extends MediaSession.Callback {
}
}

View file

@ -0,0 +1,143 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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 de.nicidienase.chaosflix.entities;
import android.util.Log;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
/*
* Movie class represents video entity with title, description, image thumbs and video url.
*
*/
public class Movie implements Serializable {
static final long serialVersionUID = 727566175075960653L;
private static long count = 0;
private long id;
private String title;
private String description;
private String bgImageUrl;
private String cardImageUrl;
private String videoUrl;
private String studio;
private String category;
public Movie() {
}
public static long getCount() {
return count;
}
public static void incCount() {
count++;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getStudio() {
return studio;
}
public void setStudio(String studio) {
this.studio = studio;
}
public String getVideoUrl() {
return videoUrl;
}
public void setVideoUrl(String videoUrl) {
this.videoUrl = videoUrl;
}
public String getBackgroundImageUrl() {
return bgImageUrl;
}
public void setBackgroundImageUrl(String bgImageUrl) {
this.bgImageUrl = bgImageUrl;
}
public String getCardImageUrl() {
return cardImageUrl;
}
public void setCardImageUrl(String cardImageUrl) {
this.cardImageUrl = cardImageUrl;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public URI getBackgroundImageURI() {
try {
Log.d("BACK MOVIE: ", bgImageUrl);
return new URI(getBackgroundImageUrl());
} catch (URISyntaxException e) {
Log.d("URI exception: ", bgImageUrl);
return null;
}
}
public URI getCardImageURI() {
try {
return new URI(getCardImageUrl());
} catch (URISyntaxException e) {
return null;
}
}
@Override
public String toString() {
return "Movie{" +
"id=" + id +
", title='" + title + '\'' +
", videoUrl='" + videoUrl + '\'' +
", backgroundImageUrl='" + bgImageUrl + '\'' +
", backgroundImageURI='" + getBackgroundImageURI().toString() + '\'' +
", cardImageUrl='" + cardImageUrl + '\'' +
'}';
}
}

View file

@ -0,0 +1,86 @@
package de.nicidienase.chaosflix.entities;
import java.util.ArrayList;
import java.util.List;
public final class MovieList {
public static final String MOVIE_CATEGORY[] = {
"Category Zero",
"Category One",
"Category Two",
"Category Three",
"Category Four",
"Category Five",
};
public static List<Movie> list;
public static List<Movie> setupMovies() {
list = new ArrayList<Movie>();
String title[] = {
"Zeitgeist 2010_ Year in Review",
"Google Demo Slam_ 20ft Search",
"Introducing Gmail Blue",
"Introducing Google Fiber to the Pole",
"Introducing Google Nose"
};
String description = "Fusce id nisi turpis. Praesent viverra bibendum semper. "
+ "Donec tristique, orci sed semper lacinia, quam erat rhoncus massa, non congue tellus est "
+ "quis tellus. Sed mollis orci venenatis quam scelerisque accumsan. Curabitur a massa sit "
+ "amet mi accumsan mollis sed et magna. Vivamus sed aliquam risus. Nulla eget dolor in elit "
+ "facilisis mattis. Ut aliquet luctus lacus. Phasellus nec commodo erat. Praesent tempus id "
+ "lectus ac scelerisque. Maecenas pretium cursus lectus id volutpat.";
String videoUrl[] = {
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/Zeitgeist/Zeitgeist%202010_%20Year%20in%20Review.mp4",
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/Demo%20Slam/Google%20Demo%20Slam_%2020ft%20Search.mp4",
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Gmail%20Blue.mp4",
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Google%20Fiber%20to%20the%20Pole.mp4",
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Google%20Nose.mp4"
};
String bgImageUrl[] = {
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/Zeitgeist/Zeitgeist%202010_%20Year%20in%20Review/bg.jpg",
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/Demo%20Slam/Google%20Demo%20Slam_%2020ft%20Search/bg.jpg",
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Gmail%20Blue/bg.jpg",
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Google%20Fiber%20to%20the%20Pole/bg.jpg",
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Google%20Nose/bg.jpg",
};
String cardImageUrl[] = {
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/Zeitgeist/Zeitgeist%202010_%20Year%20in%20Review/card.jpg",
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/Demo%20Slam/Google%20Demo%20Slam_%2020ft%20Search/card.jpg",
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Gmail%20Blue/card.jpg",
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Google%20Fiber%20to%20the%20Pole/card.jpg",
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Google%20Nose/card.jpg"
};
list.add(buildMovieInfo("category", title[0],
description, "Studio Zero", videoUrl[0], cardImageUrl[0], bgImageUrl[0]));
list.add(buildMovieInfo("category", title[1],
description, "Studio One", videoUrl[1], cardImageUrl[1], bgImageUrl[1]));
list.add(buildMovieInfo("category", title[2],
description, "Studio Two", videoUrl[2], cardImageUrl[2], bgImageUrl[2]));
list.add(buildMovieInfo("category", title[3],
description, "Studio Three", videoUrl[3], cardImageUrl[3], bgImageUrl[3]));
list.add(buildMovieInfo("category", title[4],
description, "Studio Four", videoUrl[4], cardImageUrl[4], bgImageUrl[4]));
return list;
}
private static Movie buildMovieInfo(String category, String title,
String description, String studio, String videoUrl, String cardImageUrl,
String bgImageUrl) {
Movie movie = new Movie();
movie.setId(Movie.getCount());
Movie.incCount();
movie.setTitle(title);
movie.setDescription(description);
movie.setStudio(studio);
movie.setCategory(category);
movie.setCardImageUrl(cardImageUrl);
movie.setBackgroundImageUrl(bgImageUrl);
movie.setVideoUrl(videoUrl);
return movie;
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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 de.nicidienase.chaosflix.fragments;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import de.nicidienase.chaosflix.R;
/*
* This class demonstrates how to extend ErrorFragment
*/
public class ErrorFragment extends android.support.v17.leanback.app.ErrorFragment {
private static final String TAG = "ErrorFragment";
private static final boolean TRANSLUCENT = true;
@Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
setTitle(getResources().getString(R.string.app_name));
}
public void setErrorContent() {
setImageDrawable(getResources().getDrawable(R.drawable.lb_ic_sad_cloud));
setMessage(getResources().getString(R.string.error_fragment_message));
setDefaultBackground(TRANSLUCENT);
setButtonText(getResources().getString(R.string.dismiss_error));
setButtonClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
getFragmentManager().beginTransaction().remove(ErrorFragment.this).commit();
}
});
}
}

View file

@ -0,0 +1,406 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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 de.nicidienase.chaosflix.fragments;
import android.app.Activity;
import android.media.MediaMetadataRetriever;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter;
import android.support.v17.leanback.widget.Action;
import android.support.v17.leanback.widget.ArrayObjectAdapter;
import android.support.v17.leanback.widget.ClassPresenterSelector;
import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
import android.support.v17.leanback.widget.HeaderItem;
import android.support.v17.leanback.widget.ListRow;
import android.support.v17.leanback.widget.ListRowPresenter;
import android.support.v17.leanback.widget.OnActionClickedListener;
import android.support.v17.leanback.widget.OnItemViewClickedListener;
import android.support.v17.leanback.widget.OnItemViewSelectedListener;
import android.support.v17.leanback.widget.PlaybackControlsRow;
import android.support.v17.leanback.widget.PlaybackControlsRow.FastForwardAction;
import android.support.v17.leanback.widget.PlaybackControlsRow.PlayPauseAction;
import android.support.v17.leanback.widget.PlaybackControlsRow.RepeatAction;
import android.support.v17.leanback.widget.PlaybackControlsRow.RewindAction;
import android.support.v17.leanback.widget.PlaybackControlsRow.ShuffleAction;
import android.support.v17.leanback.widget.PlaybackControlsRow.SkipNextAction;
import android.support.v17.leanback.widget.PlaybackControlsRow.SkipPreviousAction;
import android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsDownAction;
import android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsUpAction;
import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
import android.support.v17.leanback.widget.Presenter;
import android.support.v17.leanback.widget.Row;
import android.support.v17.leanback.widget.RowPresenter;
import android.util.Log;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import de.nicidienase.chaosflix.CardPresenter;
import de.nicidienase.chaosflix.R;
import de.nicidienase.chaosflix.activities.DetailsActivity;
import de.nicidienase.chaosflix.entities.Movie;
import de.nicidienase.chaosflix.entities.MovieList;
/*
* Class for video playback with media control
*/
public class PlaybackOverlayFragment extends android.support.v17.leanback.app.PlaybackOverlayFragment {
private static final String TAG = "PlaybackControlsFragmnt";
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;
private static final int CARD_WIDTH = 200;
private static final int CARD_HEIGHT = 240;
private static final int DEFAULT_UPDATE_PERIOD = 1000;
private static final int UPDATE_PERIOD = 16;
private static final int SIMULATED_BUFFERED_TIME = 10000;
private ArrayObjectAdapter mRowsAdapter;
private ArrayObjectAdapter mPrimaryActionsAdapter;
private ArrayObjectAdapter mSecondaryActionsAdapter;
private PlayPauseAction mPlayPauseAction;
private RepeatAction mRepeatAction;
private ThumbsUpAction mThumbsUpAction;
private ThumbsDownAction mThumbsDownAction;
private ShuffleAction mShuffleAction;
private FastForwardAction mFastForwardAction;
private RewindAction mRewindAction;
private SkipNextAction mSkipNextAction;
private SkipPreviousAction mSkipPreviousAction;
private PlaybackControlsRow mPlaybackControlsRow;
private ArrayList<Movie> mItems = new ArrayList<Movie>();
private int mCurrentItem;
private Handler mHandler;
private Runnable mRunnable;
private Movie mSelectedMovie;
private OnPlayPauseClickedListener mCallback;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mItems = new ArrayList<Movie>();
mSelectedMovie = (Movie) getActivity()
.getIntent().getSerializableExtra(DetailsActivity.MOVIE);
List<Movie> movies = MovieList.list;
for (int j = 0; j < movies.size(); j++) {
mItems.add(movies.get(j));
if (mSelectedMovie.getTitle().contentEquals(movies.get(j).getTitle())) {
mCurrentItem = j;
}
}
mHandler = new Handler();
setBackgroundType(BACKGROUND_TYPE);
setFadingEnabled(false);
setupRows();
setOnItemViewSelectedListener(new OnItemViewSelectedListener() {
@Override
public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
RowPresenter.ViewHolder rowViewHolder, Row row) {
Log.i(TAG, "onItemSelected: " + item + " row " + row);
}
});
setOnItemViewClickedListener(new OnItemViewClickedListener() {
@Override
public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
RowPresenter.ViewHolder rowViewHolder, Row row) {
Log.i(TAG, "onItemClicked: " + item + " row " + row);
}
});
}
@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity context) {
super.onAttach(context);
if (context instanceof OnPlayPauseClickedListener) {
mCallback = (OnPlayPauseClickedListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnPlayPauseClickedListener");
}
}
private void setupRows() {
ClassPresenterSelector ps = new ClassPresenterSelector();
PlaybackControlsRowPresenter playbackControlsRowPresenter;
if (SHOW_DETAIL) {
playbackControlsRowPresenter = new PlaybackControlsRowPresenter(
new DescriptionPresenter());
} else {
playbackControlsRowPresenter = new PlaybackControlsRowPresenter();
}
playbackControlsRowPresenter.setOnActionClickedListener(new OnActionClickedListener() {
public void onActionClicked(Action action) {
if (action.getId() == mPlayPauseAction.getId()) {
togglePlayback(mPlayPauseAction.getIndex() == PlayPauseAction.PLAY);
} else if (action.getId() == mSkipNextAction.getId()) {
next();
} else if (action.getId() == mSkipPreviousAction.getId()) {
prev();
} else if (action.getId() == mFastForwardAction.getId()) {
Toast.makeText(getActivity(), "TODO: Fast Forward", Toast.LENGTH_SHORT).show();
} else if (action.getId() == mRewindAction.getId()) {
Toast.makeText(getActivity(), "TODO: Rewind", Toast.LENGTH_SHORT).show();
}
if (action instanceof PlaybackControlsRow.MultiAction) {
((PlaybackControlsRow.MultiAction) action).nextIndex();
notifyChanged(action);
}
}
});
playbackControlsRowPresenter.setSecondaryActionsHidden(HIDE_MORE_ACTIONS);
ps.addClassPresenter(PlaybackControlsRow.class, playbackControlsRowPresenter);
ps.addClassPresenter(ListRow.class, new ListRowPresenter());
mRowsAdapter = new ArrayObjectAdapter(ps);
addPlaybackControlsRow();
addOtherRows();
setAdapter(mRowsAdapter);
}
public void togglePlayback(boolean playPause) {
if (playPause) {
startProgressAutomation();
setFadingEnabled(true);
mCallback.onFragmentPlayPause(mItems.get(mCurrentItem),
mPlaybackControlsRow.getCurrentTime(), true);
mPlayPauseAction.setIcon(mPlayPauseAction.getDrawable(PlayPauseAction.PAUSE));
} else {
stopProgressAutomation();
setFadingEnabled(false);
mCallback.onFragmentPlayPause(mItems.get(mCurrentItem),
mPlaybackControlsRow.getCurrentTime(), false);
mPlayPauseAction.setIcon(mPlayPauseAction.getDrawable(PlayPauseAction.PLAY));
}
notifyChanged(mPlayPauseAction);
}
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;
}
private void addPlaybackControlsRow() {
if (SHOW_DETAIL) {
mPlaybackControlsRow = new PlaybackControlsRow(mSelectedMovie);
} else {
mPlaybackControlsRow = new PlaybackControlsRow();
}
mRowsAdapter.add(mPlaybackControlsRow);
updatePlaybackRow(mCurrentItem);
ControlButtonPresenterSelector presenterSelector = new ControlButtonPresenterSelector();
mPrimaryActionsAdapter = new ArrayObjectAdapter(presenterSelector);
mSecondaryActionsAdapter = new ArrayObjectAdapter(presenterSelector);
mPlaybackControlsRow.setPrimaryActionsAdapter(mPrimaryActionsAdapter);
mPlaybackControlsRow.setSecondaryActionsAdapter(mSecondaryActionsAdapter);
mPlayPauseAction = new PlayPauseAction(getActivity());
mRepeatAction = new RepeatAction(getActivity());
mThumbsUpAction = new ThumbsUpAction(getActivity());
mThumbsDownAction = new ThumbsDownAction(getActivity());
mShuffleAction = new ShuffleAction(getActivity());
mSkipNextAction = new PlaybackControlsRow.SkipNextAction(getActivity());
mSkipPreviousAction = new PlaybackControlsRow.SkipPreviousAction(getActivity());
mFastForwardAction = new PlaybackControlsRow.FastForwardAction(getActivity());
mRewindAction = new PlaybackControlsRow.RewindAction(getActivity());
if (PRIMARY_CONTROLS > 5) {
mPrimaryActionsAdapter.add(mThumbsUpAction);
} else {
mSecondaryActionsAdapter.add(mThumbsUpAction);
}
mPrimaryActionsAdapter.add(mSkipPreviousAction);
if (PRIMARY_CONTROLS > 3) {
mPrimaryActionsAdapter.add(new PlaybackControlsRow.RewindAction(getActivity()));
}
mPrimaryActionsAdapter.add(mPlayPauseAction);
if (PRIMARY_CONTROLS > 3) {
mPrimaryActionsAdapter.add(new PlaybackControlsRow.FastForwardAction(getActivity()));
}
mPrimaryActionsAdapter.add(mSkipNextAction);
mSecondaryActionsAdapter.add(mRepeatAction);
mSecondaryActionsAdapter.add(mShuffleAction);
if (PRIMARY_CONTROLS > 5) {
mPrimaryActionsAdapter.add(mThumbsDownAction);
} else {
mSecondaryActionsAdapter.add(mThumbsDownAction);
}
mSecondaryActionsAdapter.add(new PlaybackControlsRow.HighQualityAction(getActivity()));
mSecondaryActionsAdapter.add(new PlaybackControlsRow.ClosedCaptioningAction(getActivity()));
}
private void notifyChanged(Action action) {
ArrayObjectAdapter adapter = mPrimaryActionsAdapter;
if (adapter.indexOf(action) >= 0) {
adapter.notifyArrayItemRangeChanged(adapter.indexOf(action), 1);
return;
}
adapter = mSecondaryActionsAdapter;
if (adapter.indexOf(action) >= 0) {
adapter.notifyArrayItemRangeChanged(adapter.indexOf(action), 1);
return;
}
}
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());
}
if (SHOW_IMAGE) {
updateVideoImage(mItems.get(mCurrentItem).getCardImageURI().toString());
}
mRowsAdapter.notifyArrayItemRangeChanged(0, 1);
mPlaybackControlsRow.setTotalTime(getDuration());
mPlaybackControlsRow.setCurrentTime(0);
mPlaybackControlsRow.setBufferedProgress(0);
}
private void addOtherRows() {
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
for (Movie movie : mItems) {
listRowAdapter.add(movie);
}
HeaderItem header = new HeaderItem(0, getString(R.string.related_movies));
mRowsAdapter.add(new ListRow(header, listRowAdapter));
}
private int getUpdatePeriod() {
if (getView() == null || mPlaybackControlsRow.getTotalTime() <= 0) {
return DEFAULT_UPDATE_PERIOD;
}
return Math.max(UPDATE_PERIOD, mPlaybackControlsRow.getTotalTime() / getView().getWidth());
}
private void startProgressAutomation() {
mRunnable = new Runnable() {
@Override
public void run() {
int updatePeriod = getUpdatePeriod();
int currentTime = mPlaybackControlsRow.getCurrentTime() + updatePeriod;
int totalTime = mPlaybackControlsRow.getTotalTime();
mPlaybackControlsRow.setCurrentTime(currentTime);
mPlaybackControlsRow.setBufferedProgress(currentTime + SIMULATED_BUFFERED_TIME);
if (totalTime > 0 && totalTime <= currentTime) {
next();
}
mHandler.postDelayed(this, updatePeriod);
}
};
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) {
mHandler.removeCallbacks(mRunnable);
}
}
@Override
public void onStop() {
stopProgressAutomation();
super.onStop();
}
protected void updateVideoImage(String uri) {
Glide.with(getActivity())
.load(uri)
.centerCrop()
.into(new SimpleTarget<GlideDrawable>(CARD_WIDTH, CARD_HEIGHT) {
@Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
mPlaybackControlsRow.setImageDrawable(resource);
mRowsAdapter.notifyArrayItemRangeChanged(0, mRowsAdapter.size());
}
});
}
// Container Activity must implement this interface
public interface OnPlayPauseClickedListener {
void onFragmentPlayPause(Movie movie, int position, Boolean playPause);
}
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());
}
}
}

View file

@ -0,0 +1,239 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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 de.nicidienase.chaosflix.fragments;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v17.leanback.app.BackgroundManager;
import android.support.v17.leanback.app.DetailsFragment;
import android.support.v17.leanback.widget.Action;
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;
import android.support.v17.leanback.widget.OnActionClickedListener;
import android.support.v17.leanback.widget.OnItemViewClickedListener;
import android.support.v17.leanback.widget.Presenter;
import android.support.v17.leanback.widget.Row;
import android.support.v17.leanback.widget.RowPresenter;
import android.support.v4.app.ActivityOptionsCompat;
import android.util.DisplayMetrics;
import android.util.Log;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import java.util.Collections;
import java.util.List;
import de.nicidienase.chaosflix.CardPresenter;
import de.nicidienase.chaosflix.DetailsDescriptionPresenter;
import de.nicidienase.chaosflix.activities.PlaybackOverlayActivity;
import de.nicidienase.chaosflix.R;
import de.nicidienase.chaosflix.Utils;
import de.nicidienase.chaosflix.activities.DetailsActivity;
import de.nicidienase.chaosflix.activities.MainActivity;
import de.nicidienase.chaosflix.entities.Movie;
import de.nicidienase.chaosflix.entities.MovieList;
/*
* LeanbackDetailsFragment extends DetailsFragment, a Wrapper fragment for leanback details screens.
* It shows a detailed view of video and its meta plus related videos.
*/
public class VideoDetailsFragment extends DetailsFragment {
private static final String TAG = "VideoDetailsFragment";
private static final int ACTION_WATCH_TRAILER = 1;
private static final int ACTION_RENT = 2;
private static final int ACTION_BUY = 3;
private static final int DETAIL_THUMB_WIDTH = 274;
private static final int DETAIL_THUMB_HEIGHT = 274;
private static final int NUM_COLS = 10;
private Movie mSelectedMovie;
private ArrayObjectAdapter mAdapter;
private ClassPresenterSelector mPresenterSelector;
private BackgroundManager mBackgroundManager;
private Drawable mDefaultBackground;
private DisplayMetrics mMetrics;
@Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate DetailsFragment");
super.onCreate(savedInstanceState);
prepareBackgroundManager();
mSelectedMovie = (Movie) getActivity().getIntent()
.getSerializableExtra(DetailsActivity.MOVIE);
if (mSelectedMovie != null) {
setupAdapter();
setupDetailsOverviewRow();
setupDetailsOverviewRowPresenter();
setupMovieListRow();
setupMovieListRowPresenter();
updateBackground(mSelectedMovie.getBackgroundImageUrl());
setOnItemViewClickedListener(new ItemViewClickedListener());
} else {
Intent intent = new Intent(getActivity(), MainActivity.class);
startActivity(intent);
}
}
@Override
public void onStop() {
super.onStop();
}
private void prepareBackgroundManager() {
mBackgroundManager = BackgroundManager.getInstance(getActivity());
mBackgroundManager.attach(getActivity().getWindow());
mDefaultBackground = getResources().getDrawable(R.drawable.default_background);
mMetrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
}
protected void updateBackground(String uri) {
Glide.with(getActivity())
.load(uri)
.centerCrop()
.error(mDefaultBackground)
.into(new SimpleTarget<GlideDrawable>(mMetrics.widthPixels, mMetrics.heightPixels) {
@Override
public void onResourceReady(GlideDrawable resource,
GlideAnimation<? super GlideDrawable> glideAnimation) {
mBackgroundManager.setDrawable(resource);
}
});
}
private void setupAdapter() {
mPresenterSelector = new ClassPresenterSelector();
mAdapter = new ArrayObjectAdapter(mPresenterSelector);
setAdapter(mAdapter);
}
private void setupDetailsOverviewRow() {
Log.d(TAG, "doInBackground: " + mSelectedMovie.toString());
final DetailsOverviewRow row = new DetailsOverviewRow(mSelectedMovie);
row.setImageDrawable(getResources().getDrawable(R.drawable.default_background));
int width = Utils.convertDpToPixel(getActivity()
.getApplicationContext(), DETAIL_THUMB_WIDTH);
int height = Utils.convertDpToPixel(getActivity()
.getApplicationContext(), DETAIL_THUMB_HEIGHT);
Glide.with(getActivity())
.load(mSelectedMovie.getCardImageUrl())
.centerCrop()
.error(R.drawable.default_background)
.into(new SimpleTarget<GlideDrawable>(width, height) {
@Override
public void onResourceReady(GlideDrawable resource,
GlideAnimation<? super GlideDrawable>
glideAnimation) {
Log.d(TAG, "details overview card image url ready: " + resource);
row.setImageDrawable(resource);
mAdapter.notifyArrayItemRangeChanged(0, mAdapter.size());
}
});
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_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),
getResources().getString(R.string.buy_2)));
mAdapter.add(row);
}
private void setupDetailsOverviewRowPresenter() {
// Set detail background and style.
DetailsOverviewRowPresenter detailsPresenter =
new DetailsOverviewRowPresenter(new DetailsDescriptionPresenter());
detailsPresenter.setBackgroundColor(getResources().getColor(R.color.selected_background));
detailsPresenter.setStyleLarge(true);
// Hook up transition element.
detailsPresenter.setSharedElementEnterTransition(getActivity(),
DetailsActivity.SHARED_ELEMENT_NAME);
detailsPresenter.setOnActionClickedListener(new OnActionClickedListener() {
@Override
public void onActionClicked(Action action) {
if (action.getId() == ACTION_WATCH_TRAILER) {
Intent intent = new Intent(getActivity(), PlaybackOverlayActivity.class);
intent.putExtra(DetailsActivity.MOVIE, mSelectedMovie);
startActivity(intent);
} else {
Toast.makeText(getActivity(), action.toString(), Toast.LENGTH_SHORT).show();
}
}
});
mPresenterSelector.addClassPresenter(DetailsOverviewRow.class, detailsPresenter);
}
private void setupMovieListRow() {
String subcategories[] = {getString(R.string.related_movies)};
List<Movie> list = MovieList.list;
Collections.shuffle(list);
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
for (int j = 0; j < NUM_COLS; j++) {
listRowAdapter.add(list.get(j % 5));
}
HeaderItem header = new HeaderItem(0, subcategories[0]);
mAdapter.add(new ListRow(header, listRowAdapter));
}
private void setupMovieListRowPresenter() {
mPresenterSelector.addClassPresenter(ListRow.class, new ListRowPresenter());
}
private final class ItemViewClickedListener implements OnItemViewClickedListener {
@Override
public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
RowPresenter.ViewHolder rowViewHolder, Row row) {
if (item instanceof Movie) {
Movie movie = (Movie) item;
Log.d(TAG, "Item: " + item.toString());
Intent intent = new Intent(getActivity(), DetailsActivity.class);
intent.putExtra(getResources().getString(R.string.movie), mSelectedMovie);
intent.putExtra(getResources().getString(R.string.should_start), true);
startActivity(intent);
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
getActivity(),
((ImageCardView) itemViewHolder.view).getMainImageView(),
DetailsActivity.SHARED_ELEMENT_NAME).toBundle();
getActivity().startActivity(intent, bundle);
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="-270"
android:endColor="@color/background_gradient_end"
android:startColor="@color/background_gradient_start"/>
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 882 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 750 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="-270"
android:endColor="@color/background_gradient_end"
android:startColor="@color/background_gradient_start"/>
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,004 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 885 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 882 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,003 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="90"
android:centerColor="#00000000"
android:endColor="#B2000000"
android:startColor="#B2000000"
android:type="linear"/>
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<fragment android:id="@+id/details_fragment"
android:name="de.nicidienase.chaosflix.fragments.VideoDetailsFragment"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.DetailsActivity"
tools:deviceIds="tv"/>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<fragment android:id="@+id/main_browse_fragment"
android:name="de.nicidienase.chaosflix.fragments.MainFragment"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.MainActivity"
tools:deviceIds="tv"
tools:ignore="MergeRootFrame"/>

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 The Android Open Source Project
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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<VideoView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"/>
<fragment
android:id="@+id/playback_controls_fragment"
android:name="de.nicidienase.chaosflix.fragments.PlaybackOverlayFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View file

@ -0,0 +1,18 @@
<resources>
<color name="background_gradient_start">#000000</color>
<color name="background_gradient_end">#DDDDDD</color>
<color name="fastlane_background">#0096a6</color>
<color name="search_opaque">#ffaa3f</color>
<color name="selected_background">#ffaa3f</color>
<color name="detail_background">#0096a6</color>
<color name="soft_opaque">#30000000</color>
<color name="img_soft_opaque">#30FF0000</color>
<color name="img_full_opaque">#00000000</color>
<color name="black_opaque">#AA000000</color>
<color name="black">#59000000</color>
<color name="white">#FFFFFF</color>
<color name="orange_transparent">#AAFADCA7</color>
<color name="orange">#FADCA7</color>
<color name="yellow">#EEFF41</color>
<color name="default_background">#3d3d3d</color>
</resources>

View file

@ -0,0 +1,40 @@
<resources>
<string name="app_name">Chaosflix</string>
<string name="browse_title">33c3 - Works for Me</string>
<string name="related_movies">Related Videos</string>
<string name="vertical_grid_title"><![CDATA[Vertical Video Grid]]></string>
<string name="error">Error</string>
<string name="ok">OK</string>
<string name="pause">Pause</string>
<string name="play">Play</string>
<string name="stop">Stop</string>
<string name="init_text">00:00</string>
<string name="play_pause_description">Play Pause Button</string>
<string name="loading">Loading&#8230;</string>
<string name="no_video_found">No video was found</string>
<string name="about_app">About DemoCast Player</string>
<string name="version">Version: %1$s</string>
<string name="popular_header">Popular Videos</string>
<string name="preferences">PREFERENCES</string>
<string name="grid_view">Grid View</string>
<string name="error_fragment">Error Fragment</string>
<string name="personal_settings">Personal Settings</string>
<string name="watch_trailer_1">Watch trailer</string>
<string name="watch_trailer_2">FREE</string>
<string name="rent_1">Rent By Day</string>
<string name="rent_2">From $1.99</string>
<string name="buy_1">Buy and Own</string>
<string name="buy_2">AT $9.99</string>
<string name="movie">Movie</string>
<string name="should_start">shouldStart</string>
<string name="start_position">startPosition</string>
<string name="search_results">Search Results</string>
<!-- Error messages -->
<string name="video_error_media_load_timeout">Media loading timed out</string>
<string name="video_error_server_inaccessible">Media server was not reachable</string>
<string name="video_error_unknown_error">Failed to load video</string>
<string name="error_fragment_message">An error occurred</string>
<string name="dismiss_error">Dismiss</string>
<string name="oops">Oops</string>
</resources>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="@style/Theme.Leanback">
</style>
</resources>

View file

@ -0,0 +1,14 @@
<resources>
<style name="Theme.Example.Leanback" parent="Theme.Leanback">
<item name="android:windowEnterTransition">@android:transition/fade</item>
<item name="android:windowExitTransition">@android:transition/fade</item>
<item name="android:windowSharedElementExitTransition">@android:transition/move</item>
<item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowContentTransitions">true</item>
<item name="android:colorPrimary">@color/search_opaque</item>
</style>
</resources>