docs: migrate Android TV content discovery
Change-Id: I35fe1e7f4f60409a0f7c5cd5bfc8ccfede4d6c20
This commit is contained in:
@@ -1,111 +0,0 @@
|
||||
page.title=Adding Search to TV Apps
|
||||
|
||||
@jd:body
|
||||
|
||||
<div id="qv-wrapper">
|
||||
<div id="qv">
|
||||
<h2>In this document</h2>
|
||||
<ol>
|
||||
<li><a href="#add-search-ui">Add Search User Interface</a></li>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<p>Users frequently have specific content in mind when using a media app. A search interface can
|
||||
help your users get to the content they want faster than browsing. The Leanback library provides a
|
||||
set of classes to enable a standard search interface within your app that is consistent with other
|
||||
search functions on TV and provides features such as voice input.</p>
|
||||
|
||||
<h2 id="add-search-ui">Add Search User Interface</h2>
|
||||
<p>When you use the BrowseFragment class for your media browsing interface, you can enable the
|
||||
search icon by setting an OnClickListener to the BrowseFragment object. The following sample code
|
||||
demonstrates this technique.</p>
|
||||
|
||||
<pre>
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.browse_activity);
|
||||
|
||||
mBrowseFragment = (BrowseFragment)
|
||||
getFragmentManager().findFragmentById(R.id.browse_fragment);
|
||||
|
||||
...
|
||||
|
||||
mBrowseFragment.setOnSearchClickedListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Intent intent = new Intent(BrowseActivity.this, SearchActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
mBrowseFragment.setAdapter(buildAdapter());
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p class="note">
|
||||
<strong>Note:</strong> You can set the color of the search icon using the
|
||||
{@code setSearchAffordanceColor()} method of {@code BrowseFragment}.
|
||||
</p>
|
||||
|
||||
<p>When a user selects the search icon, the system invokes a search activity via the defined
|
||||
Intent. Your search activity should use a linear layout containing a SearchFragment. This fragment
|
||||
must also implement the SearchFragment.SearchResultProvider interface in order to display the
|
||||
results of a search. The following code sample shows how to extend the SearchFragment class to
|
||||
provide a search interface and results:</p>
|
||||
|
||||
<pre>
|
||||
public class MySearchFragment extends SearchFragment
|
||||
implements SearchFragment.SearchResultProvider {
|
||||
|
||||
private static final int SEARCH_DELAY_MS = 300;
|
||||
private ArrayObjectAdapter mRowsAdapter;
|
||||
private Handler mHandler = new Handler();
|
||||
private SearchRunnable mDelayedLoad;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
|
||||
setSearchResultProvider(this);
|
||||
setOnItemClickedListener(getDefaultItemClickedListener());
|
||||
mDelayedLoad = new SearchRunnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectAdapter getResultsAdapter() {
|
||||
return mRowsAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newQuery) {
|
||||
mRowsAdapter.clear();
|
||||
if (!TextUtils.isEmpty(newQuery)) {
|
||||
mDelayedLoad.setSearchQuery(newQuery);
|
||||
mHandler.removeCallbacks(mDelayedLoad);
|
||||
mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
mRowsAdapter.clear();
|
||||
if (!TextUtils.isEmpty(query)) {
|
||||
mDelayedLoad.setSearchQuery(query);
|
||||
mHandler.removeCallbacks(mDelayedLoad);
|
||||
mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>This example code shown above is meant to be used with a separate {@code SearchRunnable}
|
||||
class that runs the search query on a separate thread. This technique keeps potentially
|
||||
slow-running queries from blocking the main user interface thread.</p>
|
||||
|
||||
@@ -851,6 +851,7 @@ include the action bar on devices running Android 2.1 or higher."
|
||||
|
||||
<li class="nav-section">
|
||||
<div class="nav-section-header">
|
||||
|
||||
<a href="<?cs var:toroot ?>training/tv/start/index.html"
|
||||
description="How to start building TV apps or extend your existing app to run on TV
|
||||
devices.">
|
||||
@@ -894,6 +895,24 @@ include the action bar on devices running Android 2.1 or higher."
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="nav-section">
|
||||
<div class="nav-section-header">
|
||||
<a href="<?cs var:toroot ?>training/tv/discovery/index.html"
|
||||
description="How to help users discovery content from your app.">
|
||||
Helping Users Find Content on TV</a>
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="<?cs var:toroot ?>training/tv/discovery/recommendations.html">
|
||||
Recommending TV Content</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="<?cs var:toroot ?>training/tv/discovery/in-app-search.html">
|
||||
Searching within TV Apps</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
<!-- End: Building for TV -->
|
||||
|
||||
145
docs/html/training/tv/discovery/in-app-search.jd
Normal file
145
docs/html/training/tv/discovery/in-app-search.jd
Normal file
@@ -0,0 +1,145 @@
|
||||
page.title=Searching within TV Apps
|
||||
page.tags="leanback"
|
||||
|
||||
trainingnavtop=true
|
||||
|
||||
@jd:body
|
||||
|
||||
<div id="tb-wrapper">
|
||||
<div id="tb">
|
||||
<h2>This lesson teaches you to</h2>
|
||||
<ol>
|
||||
<li><a href="#add-search-action">Add a Search Action</a></li>
|
||||
<li><a href="#add-search-ui">Add Search Input and Results</a></li>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<p>
|
||||
Users frequently have specific content in mind when using a media app on TV. If your app contains
|
||||
a large catalog of content, browsing for a specific title may not be the most efficient way for
|
||||
users to find what they are looking for. A search interface can help your users get to the
|
||||
content they want faster than browsing.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <a href="{@docRoot}tools/support-library/features.html#v17-leanback">Leanback support
|
||||
library</a> provides a set of classes to enable a standard search interface within your app that
|
||||
is consistent with other search functions on TV and provides features such as voice input.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This lesson discusses how to provide a search interface in your app using Leanback support
|
||||
library classes.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="add-search-action">Add a Search Action</h2>
|
||||
|
||||
<p>
|
||||
When you use the {@link android.support.v17.leanback.app.BrowseFragment} class for a media
|
||||
browsing interface, you can enable a search interface as a standard part of the user
|
||||
interface. The search interface is an icon that appears in the layout when you set {@link
|
||||
android.view.View.OnClickListener} on the {@link android.support.v17.leanback.app.BrowseFragment}
|
||||
object. The following sample code demonstrates this technique.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.browse_activity);
|
||||
|
||||
mBrowseFragment = (BrowseFragment)
|
||||
getFragmentManager().findFragmentById(R.id.browse_fragment);
|
||||
|
||||
...
|
||||
|
||||
mBrowseFragment.setOnSearchClickedListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Intent intent = new Intent(BrowseActivity.this, SearchActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
mBrowseFragment.setAdapter(buildAdapter());
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p class="note">
|
||||
<strong>Note:</strong> You can set the color of the search icon using the
|
||||
{@link android.support.v17.leanback.app.BrowseFragment#setSearchAffordanceColor}.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="add-search-ui">Add a Search Input and Results</h2>
|
||||
|
||||
<p>
|
||||
When a user selects the search icon, the system invokes a search activity via the defined intent.
|
||||
Your search activity should use a linear layout containing a {@link
|
||||
android.support.v17.leanback.app.SearchFragment}. This fragment must also implement the {@link
|
||||
android.support.v17.leanback.app.SearchFragment.SearchResultProvider} interface in order to
|
||||
display the results of a search.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The following code sample shows how to extend the {@link
|
||||
android.support.v17.leanback.app.SearchFragment} class to provide a search interface and results:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
public class MySearchFragment extends SearchFragment
|
||||
implements SearchFragment.SearchResultProvider {
|
||||
|
||||
private static final int SEARCH_DELAY_MS = 300;
|
||||
private ArrayObjectAdapter mRowsAdapter;
|
||||
private Handler mHandler = new Handler();
|
||||
private SearchRunnable mDelayedLoad;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
|
||||
setSearchResultProvider(this);
|
||||
setOnItemClickedListener(getDefaultItemClickedListener());
|
||||
mDelayedLoad = new SearchRunnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectAdapter getResultsAdapter() {
|
||||
return mRowsAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newQuery) {
|
||||
mRowsAdapter.clear();
|
||||
if (!TextUtils.isEmpty(newQuery)) {
|
||||
mDelayedLoad.setSearchQuery(newQuery);
|
||||
mHandler.removeCallbacks(mDelayedLoad);
|
||||
mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
mRowsAdapter.clear();
|
||||
if (!TextUtils.isEmpty(query)) {
|
||||
mDelayedLoad.setSearchQuery(query);
|
||||
mHandler.removeCallbacks(mDelayedLoad);
|
||||
mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The example code shown above is meant to be used with a separate {@code SearchRunnable} class
|
||||
that runs the search query on a separate thread. This technique keeps potentially slow-running
|
||||
queries from blocking the main user interface thread.
|
||||
</p>
|
||||
48
docs/html/training/tv/discovery/index.jd
Normal file
48
docs/html/training/tv/discovery/index.jd
Normal file
@@ -0,0 +1,48 @@
|
||||
page.title=Helping Users Find Content on TV
|
||||
|
||||
startpage=true
|
||||
|
||||
@jd:body
|
||||
|
||||
<div id="tb-wrapper">
|
||||
<div id="tb">
|
||||
<h2>Dependencies and Prerequisites</h2>
|
||||
<ul>
|
||||
<li>Android 5.0 (API level 21) or higher</li>
|
||||
</ul>
|
||||
<h2>You should also read</h2>
|
||||
<ul>
|
||||
<li><a href="{@docRoot}design/tv/index.html">
|
||||
Design for TV</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
TV devices offer many entertainment options for users. They have thousands of content options
|
||||
from apps and related content services. At the same time, most users prefer to use TVs with the
|
||||
least amount of input possible. With the amount of choice available to users, it is important for
|
||||
app developers to provide quick and easy paths for users to discover and enjoy your content.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The Android framework helps you provide a number of paths for users to discover your content,
|
||||
including recommendations on the home screen and searching within your app's content catalog.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This class shows you how to help users discover your app's content through recommendations and
|
||||
in-app searching.
|
||||
</p>
|
||||
|
||||
|
||||
<h2>Topics</h2>
|
||||
|
||||
<dl>
|
||||
<dt><b><a href="recommendations.html">Recommending TV Content</a></b></dt>
|
||||
<dd>Learn how to recommend content for users so that it appears in the recommendations row
|
||||
on the home screen of a TV device.</dd>
|
||||
|
||||
<dt><b><a href="in-app-search.html">Searching within TV Apps</a></b></dt>
|
||||
<dd>Learn how to use a built-for-TV user interface for searching within your app.</dd>
|
||||
</dl>
|
||||
@@ -1,39 +1,57 @@
|
||||
page.title=Making Recommendations
|
||||
page.title=Recommending TV Content
|
||||
page.tags="recommendation","recommend"
|
||||
|
||||
trainingnavtop=true
|
||||
|
||||
@jd:body
|
||||
|
||||
<div id="qv-wrapper">
|
||||
<div id="qv">
|
||||
<h2>In this document</h2>
|
||||
<div id="tb-wrapper">
|
||||
<div id="tb">
|
||||
<h2>This lesson teaches you to</h2>
|
||||
<ol>
|
||||
<li><a href="#service">Create a Recommendations Service</a></li>
|
||||
<li><a href="#build">Build Recommendations</a></li>
|
||||
<li><a href="#run-service">Run Recommendations Service</a></li>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
When interacting with TVs, users generally prefer to give minimal input before watching
|
||||
content. An ideal scenario for many TV users is: sit down, turn on, and watch. The fewest steps
|
||||
to get users to content they enjoy is generally the path they prefer.
|
||||
</p>
|
||||
|
||||
<p>Content recommendations appear as the first row of the TV launch screen after the first use
|
||||
of the device. This row is intended to help users quickly find content they enjoy. Contributing
|
||||
recommendations from your apps content catalog can help bring users back to your app.</p>
|
||||
|
||||
<p>
|
||||
The Android framework assists with minimum-input interaction by providing a recommendations row
|
||||
on the home screen. Content recommendations appear as the first row of the TV launch screen after
|
||||
the first use of the device. Contributing recommendations from your app's content catalog can help
|
||||
bring users back to your app.
|
||||
</p>
|
||||
|
||||
<img src="{@docRoot}preview/tv/images/home-recommendations.png" alt="" id="figure1" />
|
||||
<p class="img-caption">
|
||||
<strong>Figure 1.</strong> An example of the recommendations row.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This lesson teaches you how to create recommendations and provide them to the Android framework
|
||||
so your app content can be easily discovered and enjoyed by users.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="service">Create a Recommendations Service</h2>
|
||||
|
||||
<p>Content recommendations are created with background processing. In order for your application
|
||||
to contribute to recommendations, you create a service that periodically adds listings from your
|
||||
app's catalog to the system list of recommendations.</p>
|
||||
<p>
|
||||
Content recommendations are created with background processing. In order for your application to
|
||||
contribute to recommendations, create a service that periodically adds listings from your
|
||||
app's catalog to the system list of recommendations.
|
||||
</p>
|
||||
|
||||
<p>The following code example illustrates how to extend the {@link android.app.IntentService} to
|
||||
create a recommendation service for your application.</p>
|
||||
<p>
|
||||
The following code example illustrates how to extend {@link android.app.IntentService} to
|
||||
create a recommendation service for your application:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
public class RecommendationsService extends IntentService {
|
||||
@@ -66,9 +84,10 @@ public class RecommendationsService extends IntentService {
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>In order for this class to be recognized and run as a service, you must register this service
|
||||
using your app manifest. The following code snippet illustrates how to add this class as a
|
||||
service:</p>
|
||||
<p>
|
||||
In order for this service to be recognized by the system and run, register it using your
|
||||
app manifest. The following code snippet illustrates how to declare this class as a service:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
<manifest ... >
|
||||
@@ -81,14 +100,20 @@ public class RecommendationsService extends IntentService {
|
||||
</manifest>
|
||||
</pre>
|
||||
|
||||
|
||||
<h2 id="build">Build Recommendations</h2>
|
||||
|
||||
<p>Once it starts running, your service must create recommendations and pass them to the Android
|
||||
framework. The framework receives the recommendations as {@link android.app.Notification} objects
|
||||
that use a specific style and are marked with a specific category.</p>
|
||||
<p>
|
||||
Once your recommendation server starts running, it must create recommendations and pass them to
|
||||
the Android framework. The framework receives the recommendations as {@link
|
||||
android.app.Notification} objects that use a specific template and are marked with a specific
|
||||
category.
|
||||
</p>
|
||||
|
||||
<p>The following code example demonstrates how to get an instance of the {@link
|
||||
android.app.NotificationManager}, build a recommendation, and post it to the manager:</p>
|
||||
<p>
|
||||
The following code example demonstrates how to get an instance of the {@link
|
||||
android.app.NotificationManager}, build a recommendation, and post it to the manager:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
public class RecommendationsService extends IntentService {
|
||||
@@ -113,8 +138,11 @@ public class RecommendationsService extends IntentService {
|
||||
new NotificationCompat.Builder(context)
|
||||
.setContentTitle(movie.getTitle())
|
||||
.setContentText(movie.getDescription())
|
||||
.setContentInfo(APP_NAME)
|
||||
.setGroup("ActionMovies")
|
||||
.setSortKey("0.8")
|
||||
.setPriority(movie.getPriority())
|
||||
.setOngoing(true)
|
||||
.setColor(#FFFF2020)
|
||||
.setCategory("recommendation")
|
||||
.setLargeIcon(movie.getImage())
|
||||
.setSmallIcon(movie.getSmallIcon())
|
||||
@@ -148,11 +176,13 @@ public class RecommendationsService extends IntentService {
|
||||
|
||||
<h3 id="run-service">Run Recommendations Service</h3>
|
||||
|
||||
<p>Your app's recommendation service must run periodically in order to create current
|
||||
recommendations. In order to run your service, you should create a class that runs a timer and
|
||||
invokes it at regular intervals. The following code example extends the {@link
|
||||
<p>
|
||||
Your app's recommendation service must run periodically in order to create current
|
||||
recommendations. To run your service, create a class that runs a timer and invokes
|
||||
it at regular intervals. The following code example extends the {@link
|
||||
android.content.BroadcastReceiver} class to start periodic execution of a recommendation service
|
||||
every 12 hours:</p>
|
||||
every 12 hours:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
public class BootupReceiver extends BroadcastReceiver {
|
||||
@@ -183,10 +213,12 @@ public class BootupReceiver extends BroadcastReceiver {
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>In order for the {@link android.content.BroadcastReceiver} class to execute after a TV
|
||||
device starts up, you must register this class in your app manifest and attach an intent filter
|
||||
in order for the device boot process to complete. This sample code demonstrates how to add this
|
||||
configuration to the manifest:</p>
|
||||
<p>
|
||||
This implementation of the {@link android.content.BroadcastReceiver} class must run after start
|
||||
up of the TV device where it is installed. To accomplish this, register this class in your app
|
||||
manifest with an intent filter that listens for the completion of the device boot process. The
|
||||
following sample code demonstrates how to add this configuration to the manifest:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
<manifest ... >
|
||||
@@ -203,6 +235,6 @@ public class BootupReceiver extends BroadcastReceiver {
|
||||
|
||||
<p class="important">
|
||||
<strong>Important:</strong> Receiving a boot completed notification requires that your app
|
||||
request the {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission.
|
||||
requests the {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission.
|
||||
For more information, see {@link android.content.Intent#ACTION_BOOT_COMPLETED}.
|
||||
</p>
|
||||
Reference in New Issue
Block a user