117
Android TV: Building apps with Google’s Leanback Library

Android TV: Building apps with Google’s Leanback Library

Embed Size (px)

Citation preview

Page 1: Android TV: Building apps with  Google’s Leanback Library

Android TV:Building apps with Google’s Leanback Library

Page 2: Android TV: Building apps with  Google’s Leanback Library

Joe BirchAndroid Engineer @Buffer

@hitherejoe / hitherejoe.com

Page 3: Android TV: Building apps with  Google’s Leanback Library

What is Android TV?

Page 4: Android TV: Building apps with  Google’s Leanback Library
Page 5: Android TV: Building apps with  Google’s Leanback Library

Build on Material

Page 6: Android TV: Building apps with  Google’s Leanback Library

Build on Material Casual Consumption

Page 7: Android TV: Building apps with  Google’s Leanback Library

Build on Material Casual Consumption

Cinematic Experience

Page 8: Android TV: Building apps with  Google’s Leanback Library

Build on Material Casual Consumption

Cinematic Experience Simplicity

Page 9: Android TV: Building apps with  Google’s Leanback Library

NavigationGetting around

Page 10: Android TV: Building apps with  Google’s Leanback Library

D-Pad controls

Page 11: Android TV: Building apps with  Google’s Leanback Library

Focus based Navigation

Page 12: Android TV: Building apps with  Google’s Leanback Library
Page 13: Android TV: Building apps with  Google’s Leanback Library

Setting upGetting your project ready

Page 14: Android TV: Building apps with  Google’s Leanback Library

<uses-feature android:name="android.hardware.microphone" android:required="false"/>

<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>

<uses-feature android:name="android.software.leanback" android:required="true"/>

<activity android:name=“com.hitherejoe.vineyard.ui.main.LeanbackActivity” android:label="@string/app_name" android:theme="@style/Theme.Leanback">

<intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LEANBACK_LAUNCHER"/> </intent-filter>

</activity>

Page 15: Android TV: Building apps with  Google’s Leanback Library

github.com/hitherejoe/vineyard

github.com/hitherejoe/bourbon

Page 16: Android TV: Building apps with  Google’s Leanback Library

BrowseFragmentDisplay browsable content to the user

Page 17: Android TV: Building apps with  Google’s Leanback Library
Page 18: Android TV: Building apps with  Google’s Leanback Library

<fragment xmlns:android="http://schemas.android.com/apk/res/android" android:name=“com.hitherejoe.vineyard.ui.fragment.BrowseFragment” android:id="@+id/main_browse_fragment" android:layout_width="match_parent" android:layout_height="match_parent"/>

Page 19: Android TV: Building apps with  Google’s Leanback Library
Page 20: Android TV: Building apps with  Google’s Leanback Library

setBrandColor(ContextCompat.getColor(this, R.color.fastlane_background));

Page 21: Android TV: Building apps with  Google’s Leanback Library

Color color = ContextCompat.getColor(this, R.color.accent);setSearchAffordanceColor(color);

Page 22: Android TV: Building apps with  Google’s Leanback Library

Drawable badge = ContextCompat.getDrawable( this, R.drawable.banner_shadow);setBadgeDrawable(badge);

Page 23: Android TV: Building apps with  Google’s Leanback Library

setHeadersState(HEADERS_ENABLED);

Page 24: Android TV: Building apps with  Google’s Leanback Library

setHeadersState(HEADERS_HIDDEN);

Page 25: Android TV: Building apps with  Google’s Leanback Library

setHeadersState(HEADERS_DISABLED);

Page 26: Android TV: Building apps with  Google’s Leanback Library
Page 27: Android TV: Building apps with  Google’s Leanback Library
Page 28: Android TV: Building apps with  Google’s Leanback Library

Browse Fragment

Header Item Presenter

Header Item

List RowArray Object Adapter

Post Adapter

Page 29: Android TV: Building apps with  Google’s Leanback Library

Browse Fragment

Header Item Presenter

Header Item

List RowArray Object Adapter

Post Adapter

Page 30: Android TV: Building apps with  Google’s Leanback Library

public class IconHeaderItemPresenter extends RowHeaderPresenter {

@Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup) { // inflate layout }

@Override public void onBindViewHolder(Presenter.ViewHolder viewHolder,

Object o) { // set text, icons etc } @Override public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) { // free resources }

}

Page 31: Android TV: Building apps with  Google’s Leanback Library

public class IconHeaderItemPresenter extends RowHeaderPresenter {

@Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup) { // inflate layout }

@Override public void onBindViewHolder(Presenter.ViewHolder viewHolder,

Object o) { // set text, icons etc }

@Override public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) { // free resources }

}

Page 32: Android TV: Building apps with  Google’s Leanback Library

<android.support.v17.leanback.widget.NonOverlappingLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height=“match_parent" android:orientation="horizontal">

<ImageView android:id="@+id/header_icon" android:layout_width="32dp" android:layout_height="32dp"/>

<TextView android:id="@+id/header_label" android:layout_marginLeft="6dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/white" android:textSize=“@dimen/header_text”/>

</android.support.v17.leanback.widget.NonOverlappingLinearLayout>

Page 33: Android TV: Building apps with  Google’s Leanback Library

public class IconHeaderItemPresenter extends RowHeaderPresenter {

@Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup) { // inflate layout }

@Override public void onBindViewHolder(Presenter.ViewHolder viewHolder,

Object o) { // set text, icons etc }

@Override public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) { // free resources }

}

Page 34: Android TV: Building apps with  Google’s Leanback Library

@Overridepublic void onBindViewHolder(Presenter.ViewHolder viewHolder, Object o) { HeaderItem headerItem = ((ListRow) o).getHeaderItem();

setIconDrawable(headerItem.getName(), viewholder.iconImage);

TextView label = viewHolder.headerText; label.setText(headerItem.getName());}

Page 35: Android TV: Building apps with  Google’s Leanback Library

public class IconHeaderItemPresenter extends RowHeaderPresenter {

@Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup) { // inflate layout }

@Override public void onBindViewHolder(Presenter.ViewHolder viewHolder,

Object o) { // set text, icons etc } @Override public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) { // release bitmaps if used }

}

Page 36: Android TV: Building apps with  Google’s Leanback Library

setHeaderPresenterSelector(new PresenterSelector() { @Override public Presenter getPresenter(Object o) { return new IconHeaderItemPresenter(); }});

Page 37: Android TV: Building apps with  Google’s Leanback Library

Browse Fragment

Header Item Presenter

Header Item

List RowArray Object Adapter

Array Object Adapter

Page 38: Android TV: Building apps with  Google’s Leanback Library

Header Item

List Row

Array Object Adapter

Page 39: Android TV: Building apps with  Google’s Leanback Library

ArrayObjectAdapter rowAdapter = new ArrayObjectAdapter(this);rowAdapter.add(…);

HeaderItem header = new HeaderItem(headerPosition, tag);

mRowsAdapter.add(new ListRow(header, rowAdapter));

Page 40: Android TV: Building apps with  Google’s Leanback Library

Browse Fragment Array Object Adapter

Page 41: Android TV: Building apps with  Google’s Leanback Library

setOnItemViewClickedListener(mOnItemViewClickedListener);

setOnItemViewSelectedListener(mOnItemViewSelectedListener);

Page 42: Android TV: Building apps with  Google’s Leanback Library

@Overridepublic void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) {

// Do stuff with clicked item object

}

Page 43: Android TV: Building apps with  Google’s Leanback Library

@Overridepublic void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) {

// Do stuff with selected item object

}

Page 44: Android TV: Building apps with  Google’s Leanback Library
Page 45: Android TV: Building apps with  Google’s Leanback Library
Page 46: Android TV: Building apps with  Google’s Leanback Library

BackgroundManager backgroundManager = BackgroundManager.getInstance(getActivity());

Page 47: Android TV: Building apps with  Google’s Leanback Library

BackgroundManager backgroundManager = BackgroundManager.getInstance(getActivity());

backgroundManager.attach(getActivity().getWindow());

Page 48: Android TV: Building apps with  Google’s Leanback Library

BackgroundManager backgroundManager = BackgroundManager.getInstance(getActivity());

backgroundManager.attach(getActivity().getWindow());

backgroundManager.setBitmap(resource);

Page 49: Android TV: Building apps with  Google’s Leanback Library

BackgroundManager backgroundManager = BackgroundManager.getInstance(getActivity());

backgroundManager.attach(getActivity().getWindow());

backgroundManager.setBitmap(resource);

// Don’t forget to release!!backgroundManager.release();

Page 50: Android TV: Building apps with  Google’s Leanback Library

SearchFragmentAllow users to search for content

Page 51: Android TV: Building apps with  Google’s Leanback Library
Page 52: Android TV: Building apps with  Google’s Leanback Library

@Overridepublic boolean onQueryTextChange(String newQuery)

@Overridepublic boolean onQueryTextSubmit(String query)

Page 53: Android TV: Building apps with  Google’s Leanback Library

Post Results (Array Object Adapter)

Search Results (Array Object Adapter)

Row Adapter (Array Object Adapter)

Focused item triggers Post search

Page 54: Android TV: Building apps with  Google’s Leanback Library
Page 55: Android TV: Building apps with  Google’s Leanback Library

VerticalGridFragmentDisplay a grid of browsable content to the user

Page 56: Android TV: Building apps with  Google’s Leanback Library
Page 57: Android TV: Building apps with  Google’s Leanback Library

VerticalGridPresenter gridPresenter = new VerticalGridPresenter();

gridPresenter.setNumberOfColumns(NUM_COLUMNS);setGridPresenter(gridPresenter);

Page 58: Android TV: Building apps with  Google’s Leanback Library

PlaybackActivityDisplay media content on screen

Page 59: Android TV: Building apps with  Google’s Leanback Library
Page 60: Android TV: Building apps with  Google’s Leanback Library

mSession = new MediaSession(this, getString(R.string.app_name);mSession.setCallback(new MediaSessionCallback());mSession.setActive(true);

setMediaController(new MediaController(this, mSession.getSessionToken());

Page 61: Android TV: Building apps with  Google’s Leanback Library

PlaybackOverlayFragmentDisplay playback controls to the user

Page 62: Android TV: Building apps with  Google’s Leanback Library
Page 63: Android TV: Building apps with  Google’s Leanback Library
Page 64: Android TV: Building apps with  Google’s Leanback Library

mMediaController = getActivity().getMediaController();mMediaController.registerCallback(mMediaControllerCallback);

private class MediaControllerCallback extends MediaController.Callback {

@Override public void onPlaybackStateChanged(@NonNull PlaybackState state) { }

@Override public void onMetadataChanged(@NonNull MediaMetadata metadata) { }

}

Page 65: Android TV: Building apps with  Google’s Leanback Library

ArrayObjectAdapter (Row Adapter)

ArrayObjectAdapter (Related Posts)

ArrayObjectAdapter (Primary Actions)

ArrayObjectAdapter (Secondary Actions)

PlayBackControlsRow

Meta Data

Page 66: Android TV: Building apps with  Google’s Leanback Library

ControlButtonPresenterSelector presenterSelector = new ControlButtonPresenterSelector();

mPrimaryActionsAdapter = new ArrayObjectAdapter(presenterSelector);mSecondaryActionsAdapter = new ArrayObjectAdapter(presenterSelector);

mPlaybackControlsRow .setPrimaryActionsAdapter(mPrimaryActionsAdapter);mPlaybackControlsRow .setSecondaryActionsAdapter(mPrimaryActionsAdapter);

Page 67: Android TV: Building apps with  Google’s Leanback Library

public class Action { private Drawable mIcons;

private CharSequence mLabel1;private CharSequence mLabel2;private ArrayList mKeyCodes;…

}

Page 68: Android TV: Building apps with  Google’s Leanback Library

mPlayPauseAction = new PlayPauseAction(getActivity());mRepeatAction = new RepeatAction(getActivity());mSkipNextAction = new SkipNextAction(getActivity());mSkipPreviousAction = new SkipPreviousAction(getActivity());

mPrimaryActionsAdapter.add(mPlayPauseAction);mPrimaryActionsAdapter.add(mSkipNextAction);mPrimaryActionsAdapter.add(mSkipPreviousAction);

mSecondaryActionsAdapter.add(mRepeatAction);

Page 69: Android TV: Building apps with  Google’s Leanback Library

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(true); } else if (action.getId() == mSkipPreviousAction.getId()) { prev(true); } else if (action.getId() == mRepeatAction.getId()) { loopVideos(); } if (action instanceof PlaybackControlsRow.MultiAction) { notifyChanged(action); } } });

Page 70: Android TV: Building apps with  Google’s Leanback Library

mMediaController.getTransportControls().play();mMediaController.getTransportControls().pause;mMediaController.getTransportControls().skipToNext();mMediaController.getTransportControls().skipToPrevious();mMediaController.getTransportControls().fastForward;mMediaController.getTransportControls().rewind();

mMediaController.getTransportControls().sendCustomAction(CUSTOM_ACTION_AUTO_LOOP, null);

Page 71: Android TV: Building apps with  Google’s Leanback Library

Post item = (Post) mPlaybackControlsRow.getItem();item.description = description;item.username = username;

mPlaybackControlsRow.setTotalTime((int) duration);mPlaybackControlsRow.setImageDrawable(resource);

mPlaybackControlsRow.setCurrentTime(currentTime);mPlaybackControlsRow.setBufferedProgress(bufferedT

Page 72: Android TV: Building apps with  Google’s Leanback Library

Post item = (Post) mPlaybackControlsRow.getItem();item.description = description;item.username = username;

mPlaybackControlsRow.setTotalTime((int) duration);mPlaybackControlsRow.setImageDrawable(resource);

mPlaybackControlsRow.setCurrentTime(currentTime);mPlaybackControlsRow.setBufferedProgress(bufferedTime);

Page 73: Android TV: Building apps with  Google’s Leanback Library

ArrayObjectAdapter (Adapter Rows)

ArrayObjectAdapter (Related Posts)

ArrayObjectAdapter (Primary Actions)

ArrayObjectAdapter (Secondary Actions)PlayBackControlsRow

Meta Data

Page 74: Android TV: Building apps with  Google’s Leanback Library

GuidedStepFragmentDisplay a set of selectable options to the user

Page 75: Android TV: Building apps with  Google’s Leanback Library
Page 76: Android TV: Building apps with  Google’s Leanback Library
Page 77: Android TV: Building apps with  Google’s Leanback Library

@Overridepublic GuidanceStylist.Guidance

onCreateGuidance(Bundle savedInstanceState) {

String title = getString(…); String description = getString(…); Drawable icon = getActivity().getDrawable(…);

return new GuidanceStylist.Guidance( title, description, "", icon);

}

Page 78: Android TV: Building apps with  Google’s Leanback Library

@Overridepublic void onCreateActions( @NonNull List<GuidedAction> actions, Bundle savedInstanceState) {

GuidedAction guidedAction = new GuidedAction.Builder() .id(…) .title(…) .description(…) .checkSetId(OPTION_CHECK_SET_ID) .build(); guidedAction.setChecked(isChecked); actions.add(guidedAction);}

Page 79: Android TV: Building apps with  Google’s Leanback Library

ErrorFragmentDisplay an error message to the user

(Because things don’t always go as planned)

Page 80: Android TV: Building apps with  Google’s Leanback Library
Page 81: Android TV: Building apps with  Google’s Leanback Library

ErrorFragment errorFragment = new ErrorFragment();

errorFragment.setTitle(…);errorFragment.setMessage(…);errorFragment.setButtonText(…);errorFragment.setButtonClickListener(…);

Page 82: Android TV: Building apps with  Google’s Leanback Library

Custom ViewsBecause your app doesn’t have to look boring

Page 83: Android TV: Building apps with  Google’s Leanback Library

Tag Card

Tag Card View

Base Card View

Text View

Image View

Page 84: Android TV: Building apps with  Google’s Leanback Library

Tag Card

TagCardView cardView = new TagCardView(parent.getContext());

Tag post = (Tag) item;TagCardView cardView = (TagCardView) viewHolder.view;

if (post.tag != null) { cardView.setCardText(post.tag); cardView.setCardIcon(R.drawable.ic_tag);}

Page 85: Android TV: Building apps with  Google’s Leanback Library

Icon Card

Icon Card View

Base Card View

Text View

Image View

Text View

Page 86: Android TV: Building apps with  Google’s Leanback Library

Icon Card

IconCardView cardView = new IconCardView(parent.getContext());

Option option = (Option) item;IconCardView cardView = (IconCardView) viewHolder.view;

if (option.tag != null) { cardView.setCardIcon(R.drawable.ic_loop); cardView.setTitleText(option.title); cardView.setValueText(option.title);}

Page 87: Android TV: Building apps with  Google’s Leanback Library

Loading Card

Loading Card View

Base Card View

Progress Bar

Page 88: Android TV: Building apps with  Google’s Leanback Library

Loading Card

LoadingCardView cardView = new LoadingCardView(parent.getContext());

IconCardView cardView = (IconCardView) viewHolder.view;cardView.setIsLoading(true);

Page 89: Android TV: Building apps with  Google’s Leanback Library

Live Card

Page 90: Android TV: Building apps with  Google’s Leanback Library

Live Card

Live Card View

Base Card View

Preview Card View

Looping Video View

Progress Bar

Image View

View (Transparent Overlay)

Video View

Page 91: Android TV: Building apps with  Google’s Leanback Library

Live CardLiveCardView cardView = new LiveCardView(parent.getContext());

Post post = (Post) item;LiveCardView cardView = (LiveCardView) viewHolder.view;

if (post.videoUrl != null) { cardView.setTitleText(post.description); cardView.setContentText(post.username); cardView.setVideoUrl(post.videoUrl);

Glide.with(cardView.getContext()) .load(post.thumbnailUrl) .centerCrop() .error(mDefaultCardImage) .into(cardView.getMainImageView());}

Page 92: Android TV: Building apps with  Google’s Leanback Library

Leanback Cards

https://github.com/hitherejoe/LeanbackCards

Page 93: Android TV: Building apps with  Google’s Leanback Library
Page 94: Android TV: Building apps with  Google’s Leanback Library

Google Guidelines

Page 95: Android TV: Building apps with  Google’s Leanback Library
Page 96: Android TV: Building apps with  Google’s Leanback Library

Testing.

Page 97: Android TV: Building apps with  Google’s Leanback Library

onView(withId(R.id.title_orb)) .perform(click());

onView(withId(R.id.browse_headers)) .perform(RecyclerViewActions .actionOnItemAtPosition(i, click()));

onView(withItemText(post.description, R.id.browse_container_dock)) .perform(click());

Dig deep and remember, everything has IDs!

Page 98: Android TV: Building apps with  Google’s Leanback Library

Android N(utella?)

Page 99: Android TV: Building apps with  Google’s Leanback Library

Picture-in-Picture

Page 100: Android TV: Building apps with  Google’s Leanback Library
Page 101: Android TV: Building apps with  Google’s Leanback Library

<activity android:name=“.ui.video.VideoActivity” android:resizeableActivity="true" android:supportsPictureInPicture="true" android:configChanges= “screenSize|smallestScreenSize|screenLayout|orientation" />

Page 102: Android TV: Building apps with  Google’s Leanback Library

@Overridepublic void onActionClicked(Action action) { if (action.getId() == R.id.lb_control_picture_in_picture) { getActivity().enterPictureInPicture(); return; }}

Page 103: Android TV: Building apps with  Google’s Leanback Library

@Overridepublic void onPictureInPictureChanged(boolean inPictureInPicture) { if (inPictureInPicture) { // Hide the controls in picture-in-picture mode. } else { // Restore the playback UI based on the playback status. }}

Page 104: Android TV: Building apps with  Google’s Leanback Library

@Overridepublic void onPause() { if (mInPictureInPicture) { // Continue playback } // If paused but not in PIP, pause playback if necessary}

Page 105: Android TV: Building apps with  Google’s Leanback Library

TV Recording

Page 106: Android TV: Building apps with  Google’s Leanback Library

Sharing Code

Page 107: Android TV: Building apps with  Google’s Leanback Library
Page 108: Android TV: Building apps with  Google’s Leanback Library
Page 109: Android TV: Building apps with  Google’s Leanback Library
Page 110: Android TV: Building apps with  Google’s Leanback Library
Page 111: Android TV: Building apps with  Google’s Leanback Library

github.com/hitherejoe/bourbon

Page 112: Android TV: Building apps with  Google’s Leanback Library

What’s next?

Page 113: Android TV: Building apps with  Google’s Leanback Library

The future of TV

Page 114: Android TV: Building apps with  Google’s Leanback Library
Page 115: Android TV: Building apps with  Google’s Leanback Library
Page 116: Android TV: Building apps with  Google’s Leanback Library
Page 117: Android TV: Building apps with  Google’s Leanback Library

Resources

Official Android TV Documentation

github.com/hitherejoe/vineyard

Google Plus Android TV Community

github.com/hitherejoe/AndroidTvBoilerplategithub.com/hitherejoe/leanbackcardsmedium.com/@hitherejoe