Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f68b784 authored by Joe Fernandez's avatar Joe Fernandez Committed by Android Git Automerger
Browse files

am d13d50d8: Merge "docs: ATV Catalog Browser Update" into lmp-docs

* commit 'd13d50d8':
  docs: ATV Catalog Browser Update
parents b954cab2 d13d50d8
Loading
Loading
Loading
Loading
+229 KiB
Loading image diff...
+3 −1
Original line number Original line Diff line number Diff line
@@ -8,4 +8,6 @@ page.image=design/tv/images/focus.png


<p>These classes teach you how to build apps for TV devices.</p>
<p>These classes teach you how to build apps for TV devices.</p>


<p class="note"><strong>Note:</strong> For details on how to publish your TV apps in Google Play,  see <a href="{docRoot}distribute/googleplay/tv.html">Distributing to Android TV</a>.</p>
<p class="note"><strong>Note:</strong> For details on how to publish your TV
 No newline at end of file
apps in Google Play, see <a href="{@docRoot}distribute/googleplay/tv.html">
Distributing to Android TV</a>.</p>
 No newline at end of file
+265 −53
Original line number Original line Diff line number Diff line
@@ -11,25 +11,35 @@ trainingnavtop=true
  <h2>This lesson teaches you to</h2>
  <h2>This lesson teaches you to</h2>
  <ol>
  <ol>
    <li><a href="#layout">Create a Media Browse Layout</a></li>
    <li><a href="#layout">Create a Media Browse Layout</a></li>
    <li><a href="#header">Customize the Header Views</a></li>
    <li><a href="#lists">Display Media Lists</a></li>
    <li><a href="#lists">Display Media Lists</a></li>
    <li><a href="#background">Update the Background</a></li>
    <li><a href="#background">Update the Background</a></li>
  </ol>
  </ol>
  <h2>Try it out</h2>
  <ul>
    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android
    Leanback sample app</a></li>
  </ul>


</div>
</div>
</div>
</div>


<p>
<p>
  Media apps that run on TV need to allow users to browse its content offerings, make a
  A media app that runs on a TV needs to allow users to browse its content offerings, make a
  selection, and start playing content. The content browsing experience for apps of this type
  selection, and start playing content. The content browsing experience for apps of this type
  should be simple and intuitive, as well as visually pleasing and engaging.
  should be simple and intuitive, as well as visually pleasing and engaging.
</p>
</p>


<p>
<p>
  This lesson discusses how to use the classes provided by the <a href=
  This lesson discusses how to use the classes provided by the <a href=
  "{@docRoot}tools/support-library/features.html#v17-leanback">v17 leanback support library</a> to
  "{@docRoot}tools/support-library/features.html#v17-leanback">v17 leanback support library</a>
  implement a user interface for browsing music or videos from your app's media catalog.
  to implement a user interface for browsing music or videos from your app's media catalog.
</p>
</p>


<img itemprop="image" src="{@docRoot}images/tv/app-browse.png" alt="App main screen"/>
<p class="img-caption"><b>Figure 1.</b> The <a href="https://github.com/googlesamples/androidtv-Leanback">
Leanback sample app</a> browse fragment displays video catalog data.</p>



<h2 id="layout">Create a Media Browse Layout</h2>
<h2 id="layout">Create a Media Browse Layout</h2>


@@ -37,69 +47,270 @@ trainingnavtop=true
  The {@link android.support.v17.leanback.app.BrowseFragment} class in the leanback library
  The {@link android.support.v17.leanback.app.BrowseFragment} class in the leanback library
  allows you to create a primary layout for browsing categories and rows of media items with a
  allows you to create a primary layout for browsing categories and rows of media items with a
  minimum of code. The following example shows how to create a layout that contains a {@link
  minimum of code. The following example shows how to create a layout that contains a {@link
  android.support.v17.leanback.app.BrowseFragment}:
  android.support.v17.leanback.app.BrowseFragment} object:
</p>
</p>


<pre>
<pre>
&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
&lt;FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width=&quot;match_parent&quot;
    android:id="@+id/main_frame"
  android:layout_height=&quot;match_parent&quot;
    android:layout_width="match_parent"
  android:orientation=&quot;vertical&quot;
    android:layout_height="match_parent"&gt;
  &gt;


    &lt;fragment
    &lt;fragment
      <strong>android:name="android.support.v17.leanback.app.BrowseFragment"</strong>
        android:name="com.example.android.tvleanback.ui.MainFragment"
      android:id=&quot;@+id/browse_fragment&quot;
        android:id="@+id/main_browse_fragment"
      android:layout_width=&quot;match_parent&quot;
        android:layout_width="match_parent"
      android:layout_height=&quot;match_parent&quot;
        android:layout_height="match_parent" /&gt;
      /&gt;

&lt;/FrameLayout&gt;
</pre>

<p>The application's main activity sets this view, as shown in the following example:</p>

<pre>
public class MainActivity extends Activity {
    &#64;Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
...
</pre>

<p>The {@link android.support.v17.leanback.app.BrowseFragment} methods populate the view with the
video data and UI elements and set the layout parameters such as the icon, title, and whether
category headers are enabled.</p>

<ul>
  <li>See <a href="#set-ui">Set UI Elements</a> for more information about setting up UI elements.</li>
  <li>See <a href="#hide-heads">Hide or Disable Headers</a> for more information about hiding the
  headers.</li>
</ul>

<p>The application's subclass that implements the
{@link android.support.v17.leanback.app.BrowseFragment} methods also sets
up event listeners for user actions on the UI elements, and prepares the background
manager, as shown in the following example:</p>

<pre>
public class MainFragment extends BrowseFragment implements
        LoaderManager.LoaderCallbacks&lt;HashMap&lt;String, List&lt;Movie&gt;&gt;&gt; {

...

    &#64;Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        loadVideoData();

        prepareBackgroundManager();
        setupUIElements();
        setupEventListeners();
    }
...

    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);
    }

    private void setupUIElements() {
        setBadgeDrawable(getActivity().getResources()
            .getDrawable(R.drawable.videos_by_google_banner));
        // Badge, when set, takes precedent over title
        setTitle(getString(R.string.browse_title));
        setHeadersState(HEADERS_ENABLED);
        setHeadersTransitionOnBackEnabled(true);
        // set headers background color
        setBrandColor(getResources().getColor(R.color.fastlane_background));
        // set search icon color
        setSearchAffordanceColor(getResources().getColor(R.color.search_opaque));
    }

    private void loadVideoData() {
        VideoProvider.setContext(getActivity());
        mVideosUrl = getActivity().getResources().getString(R.string.catalog_url);
        getLoaderManager().initLoader(0, null, this);
    }

    private void setupEventListeners() {
        setOnSearchClickedListener(new View.OnClickListener() {

            &#64;Override
            public void onClick(View view) {
                Intent intent = new Intent(getActivity(), SearchActivity.class);
                startActivity(intent);
            }
        });

        setOnItemViewClickedListener(new ItemViewClickedListener());
        setOnItemViewSelectedListener(new ItemViewSelectedListener());
    }
...
</pre>

<h3 id="set-ui">Set UI Elements</h2>

<p>In the sample above, the private method <code>setupUIElements()</code> calls several of the
{@link android.support.v17.leanback.app.BrowseFragment} methods to style the media catalog browser:
</p>

<ul>
  <li>{@link android.support.v17.leanback.app.BrowseFragment#setBadgeDrawable(android.graphics.drawable.Drawable) setBadgeDrawable()}
  places the specified drawable resource in the upper-right corner of the browse fragment, as
  shown in figures 1 and 2. This method replaces the title string with the
  drawable resource, if {@code setTitle()} is also called. The drawable resource should be 52dps
  tall.</li>
  <li>{@link android.support.v17.leanback.app.BrowseFragment#setTitle(java.lang.String) setTitle()}
  sets the title string in the upper-right corner of the browse fragment, unless
  {@code setBadgeDrawable()} is called.</li>
  <li>{@link android.support.v17.leanback.app.BrowseFragment#setHeadersState(int) setHeadersState()}
  and {@link android.support.v17.leanback.app.BrowseFragment#setHeadersTransitionOnBackEnabled(boolean) setHeadersTransitionOnBackEnabled()} hide or disable the headers. See
  <a href="#hide-heads">Hide or Disable Headers</a> for more information.
  </li>
  <li>{@link android.support.v17.leanback.app.BrowseFragment#setBrandColor(int) setBrandColor()}
  sets the background color for UI elements in the browse fragment, specifically the header
  section background color, with the specified color value.</li>
  <li>{@link android.support.v17.leanback.app.BrowseFragment#setSearchAffordanceColor(int) setSearchAffordanceColor()}
  sets the color of the search icon with the specified color value. The search icon
  appears in the upper-left corner of the browse fragment, as shown in figures 1 and 2.</li>
</ul>

<h2 id="header">Customize the Header Views</h2>

<p>The browse fragment shown in figure 1 lists the video category names (the row headers) in the
left pane. Text views display these category names from the video database. You can customize the
header to include additional views in a more complex layout. The following sections show how to
include an image view that displays an icon next to the category name, as shown in figure 2.</p>

<img itemprop="image" src="{@docRoot}images/tv/custom-head.png" alt="App main screen"/>
<p class="img-caption"><b>Figure 2.</b> The row headers in the browse fragment, with both an icon
and a text label.</p>

<p>The layout for the row header is defined as follows:</p>

<pre>
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"&gt;

    &lt;ImageView
        android:id="@+id/header_icon"
        android:layout_width="32dp"
        android:layout_height="32dp" /&gt;
    &lt;TextView
        android:id="@+id/header_label"
        android:layout_marginTop="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" /&gt;

&lt;/LinearLayout&gt;
&lt;/LinearLayout&gt;
</pre>
</pre>


<p>
<p>Use a {@link android.support.v17.leanback.widget.Presenter} and implement the
  In order to work with this layout in an activity, retrieve the {@link
abstract methods to create, bind, and unbind the view holder. The following
  android.support.v17.leanback.app.BrowseFragment} element from the layout. Use the methods in this
example shows how to bind the viewholder with two views, an
  class to set display parameters such as the icon, title, and whether category headers are enabled.
{@link android.widget.ImageView} and a {@link android.widget.TextView}.
  The following code sample demonstrates how to set the layout parameters for a {@link
  android.support.v17.leanback.app.BrowseFragment} in a layout:
</p>
</p>


<pre>
<pre>
public class BrowseMediaActivity extends Activity {
public class IconHeaderItemPresenter extends Presenter {
    &#64;Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup) {
        LayoutInflater inflater = (LayoutInflater) viewGroup.getContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);


    public static final String TAG ="BrowseActivity";
        View view = inflater.inflate(R.layout.icon_header_item, null);


    protected BrowseFragment mBrowseFragment;
        return new ViewHolder(view);
    }


    &#64;Override
    &#64;Override
    protected void onCreate(Bundle savedInstanceState) {
    public void onBindViewHolder(ViewHolder viewHolder, Object o) {
        super.onCreate(savedInstanceState);
        HeaderItem headerItem = ((ListRow) o).getHeaderItem();
        setContentView(R.layout.browse_fragment);
        View rootView = viewHolder.view;


        final FragmentManager fragmentManager = getFragmentManager();
        ImageView iconView = (ImageView) rootView.findViewById(R.id.header_icon);
        <strong>mBrowseFragment = (BrowseFragment) fragmentManager.findFragmentById(
        Drawable icon = rootView.getResources().getDrawable(R.drawable.ic_action_video, null);
                R.id.browse_fragment);</strong>
        iconView.setImageDrawable(icon);


        // Set display parameters for the BrowseFragment
        TextView label = (TextView) rootView.findViewById(R.id.header_label);
        mBrowseFragment.setHeadersState(BrowseFragment.HEADERS_ENABLED);
        label.setText(headerItem.getName());
        mBrowseFragment.setTitle(getString(R.string.app_name));
    }
        mBrowseFragment.setBadgeDrawable(getResources().getDrawable(
                R.drawable.ic_launcher));
        mBrowseFragment.setBrowseParams(params);


    &#64;Override
    public void onUnbindViewHolder(ViewHolder viewHolder) {
    // no op
    }
    }
}
}
</pre>
</pre>


<p>This example shows how to define the presenter for a complex layout with
multiple views, and you could use this pattern to do something even more complex.
However, an easier way to combine a {@link android.widget.TextView} with a
drawable resource is to use the <a href="{@docRoot}reference/android/widget/TextView.html#attr_android:drawableLeft">
{@code TextView.drawableLeft}</a> attribute. Doing it this way, you don't need the
{@link android.widget.ImageView} shown here.</p>

<p>In the {@link android.support.v17.leanback.app.BrowseFragment} implementation that displays the
catalog browser, use the {@link android.support.v17.leanback.app.BrowseFragment#setHeaderPresenterSelector(android.support.v17.leanback.widget.PresenterSelector) setHeaderPresenterSelector()}
method to set the presenter for the row header, as shown in the following example.</p>

<pre>
setHeaderPresenterSelector(new PresenterSelector() {
    &#64;Override
    public Presenter getPresenter(Object o) {
        return new IconHeaderItemPresenter();
    }
});
</pre>


<h2 id="lists">Displaying Media Lists</h2>
<h3 id="hide-heads">Hide or Disable Headers</h3>

<p>Sometimes you may not want the row headers to appear: when there aren't enough categories to
require a scrollable list, for example. Call the {@link android.support.v17.leanback.app.BrowseFragment#setHeadersState(int) BrowseFragment.setHeadersState()}
method during the fragment's {@link android.app.Fragment#onActivityCreated(android.os.Bundle) onActivityCreated()}
method to hide or disable the row headers. The {@link android.support.v17.leanback.app.BrowseFragment#setHeadersState(int) setHeadersState()}
method sets the initial state of the headers in the browse fragment given one of the following
constants as a parameter:</p>

<ul>
  <li>{@link android.support.v17.leanback.app.BrowseFragment#HEADERS_ENABLED} - When the browse
  fragment activity is created, the headers are enabled and shown by default. The headers appear as
  shown in figures 1 and 2 on this page.</li>
  <li>{@link android.support.v17.leanback.app.BrowseFragment#HEADERS_HIDDEN} - When the browse
  fragment activity is created, headers are enabled and hidden by default. The header section of the
  screen is collapsed, as shown in <a href="{@docRoot}training/tv/playback/card.html#collapsed">
  figure 1</a> of <a href="{@docRoot}training/tv/playback/card.html">Providing a Card View</a>. The
  user can select the collapsed header section to expand it.</li>
  <li>{@link android.support.v17.leanback.app.BrowseFragment#HEADERS_DISABLED} - When the browse
  fragment activity is created, headers are disabled by default and are never displayed.</li>
</ul>

<p>If either {@link android.support.v17.leanback.app.BrowseFragment#HEADERS_ENABLED} or
{@link android.support.v17.leanback.app.BrowseFragment#HEADERS_HIDDEN} is set, you can call
{@link android.support.v17.leanback.app.BrowseFragment#setHeadersTransitionOnBackEnabled(boolean) setHeadersTransitionOnBackEnabled()}
to support moving back to the row header from a selected content item in the row. This is enabled by
default (if you don't call the method), but if you want to handle the back movement yourself, you
should pass the value <code>false</code> to {@link android.support.v17.leanback.app.BrowseFragment#setHeadersTransitionOnBackEnabled(boolean) setHeadersTransitionOnBackEnabled()}
and implement your own back stack handling.</p>

<h2 id="lists">Display Media Lists</h2>


<p>
<p>
  The {@link android.support.v17.leanback.app.BrowseFragment} allows you to define and display
  The {@link android.support.v17.leanback.app.BrowseFragment} class allows you
  browsable media content categories and media items from a media catalog using adapters and
  to define and display browsable media content categories and media items from
  presenters. Adapters enable you to connect to local or online data sources that contain your
  a media catalog using adapters and presenters. Adapters enable you to connect
  media catalog information. Presenters hold data about media items and provide layout information
  to local or online data sources that contain your media catalog information.
  for displaying an item on screen.
  Adapters use presenters to create views and bind data to those views for
  displaying an item on screen.
</p>
</p>


<p>
<p>
@@ -131,11 +342,12 @@ public class StringPresenter extends Presenter {
</pre>
</pre>


<p>
<p>
  Once you have constructed a presenter class for your media items, you can build and attach an
  Once you have constructed a presenter class for your media items, you can build
  adapter to the {@link android.support.v17.leanback.app.BrowseFragment} to display those items on
  an adapter and attach it to the {@link android.support.v17.leanback.app.BrowseFragment}
  screen for browsing by the user. The following example code demonstrates how to construct an
  to display those items on screen for browsing by the user. The following example
  adapter to display categories and items in those categories using the {@code StringPresenter}
  code demonstrates how to construct an adapter to display categories and items
  class shown in the previous code example:
  in those categories using the {@code StringPresenter} class shown in the
  previous code example:
</p>
</p>


<pre>
<pre>
@@ -158,7 +370,7 @@ private void buildRowsAdapter() {
        listRowAdapter.add("Media Item 1");
        listRowAdapter.add("Media Item 1");
        listRowAdapter.add("Media Item 2");
        listRowAdapter.add("Media Item 2");
        listRowAdapter.add("Media Item 3");
        listRowAdapter.add("Media Item 3");
        HeaderItem header = new HeaderItem(i, "Category " + i, null);
        HeaderItem header = new HeaderItem(i, "Category " + i);
        mRowsAdapter.add(new ListRow(header, listRowAdapter));
        mRowsAdapter.add(new ListRow(header, listRowAdapter));
    }
    }


@@ -170,15 +382,15 @@ private void buildRowsAdapter() {
  This example shows a static implementation of the adapters. A typical media browsing application
  This example shows a static implementation of the adapters. A typical media browsing application
  uses data from an online database or web service. For an example of a browsing application that
  uses data from an online database or web service. For an example of a browsing application that
  uses data retrieved from the web, see the
  uses data retrieved from the web, see the
  <a href="http://github.com/googlesamples/androidtv-leanback">Android TV</a> sample app.
  <a href="http://github.com/googlesamples/androidtv-leanback">Android Leanback sample app</a>.
</p>
</p>


<h2 id="background">Update the Background</h2>
<h2 id="background">Update the Background</h2>


<p>
<p>
  In order to add visual interest to a media-browsing app on TV, you can update the background
  In order to add visual interest to a media-browsing app on TV, you can update the background
  image as users browse through content. This technique can make interaction with your app feel
  image as users browse through content. This technique can make interaction with your app more
  more cinematic and enjoyable for users.
  cinematic and enjoyable.
</p>
</p>


<p>
<p>
@@ -211,8 +423,8 @@ protected OnItemViewSelectedListener getDefaultItemViewSelectedListener() {
        &#64;Override
        &#64;Override
        public void onItemSelected(Object item, Row row) {
        public void onItemSelected(Object item, Row row) {
            if (item instanceof Movie ) {
            if (item instanceof Movie ) {
                URI uri = ((Movie)item).getBackdropURI();
                Drawable background = ((Movie)item).getBackdropDrawable();
                updateBackground(uri);
                updateBackground(background);
            } else {
            } else {
                clearBackground();
                clearBackground();
            }
            }
+4 −6
Original line number Original line Diff line number Diff line
@@ -32,9 +32,10 @@ class used in this lesson displays an image for the content along with the media
Android Leanback sample app</a>, available on GitHub. Use this sample code to start your own
Android Leanback sample app</a>, available on GitHub. Use this sample code to start your own
app.</p>
app.</p>


<img itemprop="image" src="{@docRoot}images/tv/app-browse.png" alt="App main screen"/>
<img itemprop="image" src="{@docRoot}images/tv/card-view.png" alt="App card view" id="collapsed"/>
<p class="img-caption"><b>Figure 1.</b> The <a href="https://github.com/googlesamples/androidtv-Leanback">
<p class="img-caption"><b>Figure 1.</b> The <a href="https://github.com/googlesamples/androidtv-Leanback">
Leanback sample app</a> browse fragment with a card presenter displaying card view objects.</p>
Leanback sample app</a> image card view when selected.</p>



<h2 id="presenter">Create a Card Presenter</h2>
<h2 id="presenter">Create a Card Presenter</h2>


@@ -147,10 +148,7 @@ and {@link android.view.View#setFocusableInTouchMode(boolean) setFocusableInTouc
</pre>
</pre>


<p>When the user selects the {@link android.support.v17.leanback.widget.ImageCardView}, it expands
<p>When the user selects the {@link android.support.v17.leanback.widget.ImageCardView}, it expands
to reveal its text area with the background color you specify, as shown in figure 2.</p>
to reveal its text area with the background color you specify, as shown in figure 1.</p>


<img itemprop="image" src="{@docRoot}images/tv/card-view.png" alt="App card view"/>
<p class="img-caption"><b>Figure 2.</b> The <a href="https://github.com/googlesamples/androidtv-Leanback">
Leanback sample app</a> image card view when selected.</p>