Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Bringing Your App to the Living Room: Android D...

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest. →

Bringing Your App to the Living Room: Android Development on Amazon Fire TV

Mobile development is not just about mobile devices anymore: Android scaled up from mobile devices to the TV screen, and developers have now the occasion to start building for a brand new use case: the 10-foot experience. In this session, we cover what's needed to bring your Android app to the living room: we’ll dive into the Leanback Android support library and understand how to take advantage of the big TV screen while using new UI patterns for app navigation through the remote, and how to run your first TV app on Amazon Fire TV.

Avatar for Mario Viviani

Mario Viviani

May 12, 2016

More Decks by Mario Viviani

Other Decks in Technology

Transcript

  1. MARIO VIVIANI T E C H N O L O

    G Y E V A N G E L I S T, A M A Z O N A P P S T O R E U K @mariuxtheone http://www.linkedin.com/in/marioviviani ANDROID DEVELOPMENT ON AMAZ ON FIRE TV
  2. I T ’ S A - M E ! Ma

    r io V ivia n i Technology Evangelist, Amazon Appstore UK @mariuxtheone Android Developer from 2010 95+ apps published 12,000,000+ downloads Google Developer Expert 2013-15 Startup Founder, Co-Worker Speaker at: Droidcon, Android Dev Days, Google I/O 2015
  3. bit.ly/firetvspecs TV TV Stick 4K compatible FullHD Quad-core CPU Dual-core

    CPU 2 GB RAM 1 GB RAM (2160p) (1080p) WiFi – Bluetooth 4.1 WiFi – Bluetooth 3.0 8 GB Internal Storage (actual formatted capacity will be less) 8 GB Internal Storage (actual formatted capacity will be less) USB-A and MicroSD slot MicroUSB (power only)
  4. dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:recyclerview-v7:23.1.1' compile

    'com.android.support:leanback-v17:23.1.1' compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.github.bumptech.glide:glide:3.4.+' } Gradle Dependencies
  5. public class MainFragment extends BrowseFragment { private void loadRows() {

    List<Movie> list = MovieList.setupMovies(); CardPresenter cardPresenter = new CardPresenter(); //Create the adapter for the row and add all the movies ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter); for (Movie movie:list) { listRowAdapter.add(movie); } //Create the header of this row HeaderItem header = new HeaderItem(0, "Category Name"); ...
  6. public class MainFragment extends BrowseFragment { ... //add the ListRowAdapter

    to the RowsAdapter ArrayObjectAdapter rowsAdapter = new ArrayObjectAdapter(new ListRowPresenter()); rowsAdapter.add(new ListRow(header, listRowAdapter)); setAdapter(mRowsAdapter); } }
  7. public ViewHolder onCreateViewHolder(ViewGroup parent) { ... ImageCardView cardView = new

    ImageCardView(parent.getContext); cardView.setFocusable(true); cardView.setFocusableInTouchMode(true); return new ViewHolder(cardView); ... } public class CardPresenter extends Presenter { CardPresenter
  8. CardPresenter public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) { Movie movie

    = (Movie) item; ImageCardView cardView = (ImageCardView) viewHolder.view; if (movie.getCardImageUrl() != null) { cardView.setTitleText(movie.getTitle()); cardView.setContentText(movie.getDescription()); Glide.with(viewHolder.view.getContext()) .load(movie.getCardImageUrl()) .centerCrop() .into(cardView.getMainImageView()); } }
  9. private void setupDetailsOverviewRow() { final DetailsOverviewRow row = new DetailsOverviewRow(mSelectedMovie);

    ... row.setImageDrawable(R.drawable.default_background)); row.addAction(new Action(ACTION_WATCH_TRAILER, “Watch Trailer”, “FREE”))); mAdapter.add(row); } DetailsOverviewRow
  10. 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()); } } } DescriptionPresenter
  11. 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()); } } } DescriptionPresenter
  12. PlaybackOverlayActivity - Components public class PlaybackOverlayActivity extends Activity implements PlaybackOverlayFragment.OnPlayPauseClickedListener

    { private VideoView mVideoView; private LeanbackPlaybackState mPlaybackState; private MediaSession mSession;
  13. PlaybackOverlayActivity - MediaSession @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

    setContentView(R.layout.playback_controls); ... mSession = new MediaSession(this, "LeanbackSampleApp"); mSession.setCallback(new MediaSessionCallback()); mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS ); mSession.setActive(true); }
  14. PlaybackOverlayActivity – Remote @Override public boolean onKeyUp(int keyCode, KeyEvent event)

    { PlaybackOverlayFragment playbackOverlayFragment = findFragmentById(R.id.playback_controls_fragment); switch (keyCode) { ... case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: if (mPlaybackState == LeanbackPlaybackState.PLAYING) { playbackOverlayFragment.togglePlayback(false); } else { playbackOverlayFragment.togglePlayback(true); } return true; ... } }
  15. PlaybackOverlayActivity – Play/Pause public void onFragmentPlayPause(Movie movie, int position, Boolean

    playPause) { mVideoView.setVideoPath(movie.getVideoUrl()); ... if (mPlaybackState != LeanbackPlaybackState.PLAYING) { mPlaybackState = LeanbackPlaybackState.PLAYING; if (position > 0) { mVideoView.seekTo(position); mVideoView.start(); } ... updatePlaybackState(position); updateMetadata(movie); }