am c27d5fd6: am 7cec35ef: Merge "docs: b/18122848 [DAC] Android TV - Recommendation card" into lmp-docs

* commit 'c27d5fd6a88b37226c02e67d6c86c75da47d5d9d':
  docs: b/18122848 [DAC] Android TV - Recommendation card
This commit is contained in:
Joe Fernandez
2014-12-20 00:40:59 +00:00
committed by Android Git Automerger
4 changed files with 241 additions and 106 deletions

View File

@@ -38,7 +38,7 @@ see <a href="/distribute/googleplay/tv.html">Distributing to Android TV</a>.</p>
<p>To learn more about searching within your app, see
<a href="{@docRoot}training/tv/discovery/in-app-search.html">Searching within TV Apps</a>.
<h2>Recommendations</h2>
<h2 id="recommendations">Recommendations</h2>
<p>The recommendations row on Android TV is a central feature of the Home Screen that allows
users quick access to dynamic and relevant content for their media-consumption activities. The

View File

@@ -15,24 +15,16 @@ page.title=UI Patterns for TV
<img src="{@docRoot}design/tv/images/focus.png" alt="TV navigation and focus diagram" />
<p>A key aspect of making your application work well with a D-Pad controller is to make sure
<p>A key aspect of making your application work well with a D-pad controller is to make sure
that there is always an object that is obviously in focus. Your app must clearly indicate
what object is focused, so users can easily see what action they can take. Use scale, shadow
brightness, opacity, animation or a combination of these attributes to help users see a focused
object.</p>
<h2 id="banner">App and Game Banners</h3>
<h2>Icons</h2>
<p>Apps on TV devices require some additional icon images for presentation in the system
user interface, including home screen launcher images (banners) and recommendation icons.
The visual specifications for these icons are shown below.</p>
<h3 id="banner">Banners</h3>
<p>App Banners represent your app on the home screen of TV devices and serve and as a way for
users to launch your app. Here are specific requirements for a banner image:
<p>App Banners represent your app or game on the home screens of TV devices and serve and as a way for
users to launch your app. Here are the specific requirements for a banner image:
</p>
<ul>
@@ -44,45 +36,97 @@ page.title=UI Patterns for TV
<p>See <a href="{@docRoot}training/tv/start/start.html#banner">Provide a home screen banner</a>
in Get Started with TV Apps for more information.</p>
<h3>Recommendation Icons</h3>
<h2 id="recommendation">Recommendations</h2>
<p>Recommendation cards include a small icon that is imposed over a colored background.
An example and specifications for this icon are shown below:</p>
<p>The first row of the Android TV home screen displays cards for content recommended by applications.
Your application provides these recommendations, as described in <a href="{@docRoot}training/tv/discovery/recommendations.html">
</a>. For a visual overview of recommendations, see <a href="design/tv/index.html#recommendations">
Design for Android TV</a>.</p>
<img src="{@docRoot}design/tv/images/icon.png" alt="Recommendation icon examples" />
<div class="layout-content-row">
<div class="layout-content-col span-8 with-callouts">
<p>Here are the requirements for recommendation icons:</p>
<p>The design elements of the recommendation card are as follows:</p>
<ol>
<li><strong>Large icon</strong></li>
<li><strong>Content title</strong></li>
<li><strong>Content text</strong></li>
<li><strong>Small icon</strong></li>
</ol>
<p>The design specifications for these elements are described below.</p>
<p>You can also set a background image (not shown) and the color of the card's text area in the
recommendation notification. See <a href="{@docRoot}training/tv/discovery/recommendations.html">
Recommendations</a> for more information.</p>
</div>
<div class="layout-content-col span-5">
<img src="{@docRoot}images/tv/recommend-card.png">
</div>
</div>
<h3>Background Image</h3>
<p>The background image also appears behind the recommendations
row and fills the Android TV home screen when the user selects the recommendation card. This image
should be different than the one provided for the large icon, and meet the following specifications:</p>
<ul>
<li>Monocolor: size 16x16dp, white (#fff) icon with transparent background, PNG format</li>
<li>Graphics should be centered within the icon image</li>
<li>Measure 2016 x 1134 pixels (1920 x 1080 plus 5% margin for for motion)</li>
<li id="solid-background">Must not be transparent</li>
</ul>
<p class="note">
<strong>Note:</strong> Your app icon image may be desaturated and blended for some card
displays.
<strong>Note:</strong> If the background image does not meet the size requirements, the system
scales it to fit.
</p>
<h2>Background Images</h2>
<p>Background images are displayed in the background of your app to provide additional visual
interest, information, or branding. The user interface widgets provided in the <a href="{@docRoot}tools/support-library/features.html#v17-leanback">v17 leanback support
<p>The user interface widgets provided in the
<a href="{@docRoot}tools/support-library/features.html#v17-leanback">v17 leanback support
library</a> provide specific support for background images and for updating them as items gain
and lose focus. The specific requirements for background images on TV devices is that they
should be full color and a size of 1920 x 1080 pixels.
and lose focus.
</p>
<p class="note" id="solid-background">
<strong>Important:</strong> Background images must not be transparent. Your must not allow any
portion of another app to be seen through your app.
</p>
<h3 id="icons">Icons</h3>
<h4>Large icon</h4>
<p>Typically, the large icon is an image of the content for the recommendation. It appears
above a colored area that contains the recommendation content title and text. This image should be
different from that which you provide for the background image, and conform to the following
specifications:</p>
<ul>
<li>Height: 176dp or more</li>
<li>Minimum width: 2/3 of the height (117dp for an image 176dp in height)</li>
<li>Max width: 4/3 of the height (234dp for an image 176dp in height)</li>
<li>Must not be transparent</li>
</ul>
<p class="note">
<strong>Note:</strong> If you background image does not meet the size requirements, it is scaled
to fit.
<strong>Note:</strong> If the large icon does not meet the size requirements, the system
scales it to fit.
</p>
<h4>Small icon</h4>
<p>Recommendation cards include a small icon that is imposed over a colored background. The icon and
background color display at 100% opacity when the card is selected, and at 50% opacity when not
selected.</p>
<img src="{@docRoot}design/tv/images/icon.png" alt="Recommendation icon examples" />
<p>Here are the requirements for recommendation small icons:</p>
<ul>
<li>Flat image</li>
<li>Monocolor: size 16x16dp, white (#fff) icon with transparent background, PNG format</li>
<li>Graphics should be centered within the icon image</li>
</ul>
<h2>Audio Feedback</h2>
<p>Sounds on Android TV bring a cinematic quality to the interaction experience. You should

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

View File

@@ -14,6 +14,11 @@ trainingnavtop=true
<li><a href="#build">Build Recommendations</a></li>
<li><a href="#run-service">Run Recommendations Service</a></li>
</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>
@@ -25,7 +30,7 @@ trainingnavtop=true
<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
on the home screen. Content recommendations appear as the first row of the TV home 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>
@@ -37,7 +42,9 @@ trainingnavtop=true
<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.
so users can easily discover and enjoy your app content. This discussion describes some code from
the <a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android
Leanback sample app</a>.
</p>
@@ -46,7 +53,7 @@ trainingnavtop=true
<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.
app's catalog to the system's list of recommendations.
</p>
<p>
@@ -54,26 +61,50 @@ trainingnavtop=true
create a recommendation service for your application:
</p>
<p class="code-caption">
<a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/java/com/example/android/tvleanback/UpdateRecommendationsService.java" target="_blank">
UpdateRecommendationsService.java</a>
</p>
<pre>
public class RecommendationsService extends IntentService {
public class UpdateRecommendationsService extends IntentService {
private static final String TAG = "UpdateRecommendationsService";
private static final int MAX_RECOMMENDATIONS = 3;
public RecommendationsService() {
public UpdateRecommendationsService() {
super("RecommendationService");
}
&#64;Override
protected void onHandleIntent(Intent intent) {
MovieDatabase database = MovieDatabase.instance(getApplicationContext());
List<Movie> recommendations = database.recommendations();
Log.d(TAG, "Updating recommendation cards");
HashMap&lt;String, List&lt;Movie&gt;&gt; recommendations = VideoProvider.getMovieList();
if (recommendations == null) return;
int count = 0;
try {
for (Movie movie : recommendations) {
// build the individual content recommendations
buildRecommendation(getApplicationContext(), movie);
RecommendationBuilder builder = new RecommendationBuilder()
.setContext(getApplicationContext())
.setSmallIcon(R.drawable.videos_by_google_icon);
for (Map.Entry&lt;String, List&lt;Movie&gt;&gt; entry : recommendations.entrySet()) {
for (Movie movie : entry.getValue()) {
Log.d(TAG, "Recommendation - " + movie.getTitle());
builder.setBackground(movie.getCardImageUrl())
.setId(count + 1)
.setPriority(MAX_RECOMMENDATIONS - count)
.setTitle(movie.getTitle())
.setDescription(getString(R.string.popular_header))
.setImage(movie.getCardImageUrl())
.setIntent(buildPendingIntent(movie))
.build();
if (++count >= MAX_RECOMMENDATIONS) {
break;
}
}
if (++count >= MAX_RECOMMENDATIONS) {
break;
}
@@ -82,6 +113,21 @@ public class RecommendationsService extends IntentService {
Log.e(TAG, "Unable to update recommendation", e);
}
}
private PendingIntent buildPendingIntent(Movie movie) {
Intent detailsIntent = new Intent(this, DetailsActivity.class);
detailsIntent.putExtra("Movie", movie);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(DetailsActivity.class);
stackBuilder.addNextIntent(detailsIntent);
// Ensure a unique PendingIntents, otherwise all recommendations end up with the same
// PendingIntent
detailsIntent.setAction(Long.toString(movie.getId()));
PendingIntent intent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
return intent;
}
}
</pre>
@@ -90,125 +136,165 @@ public class RecommendationsService extends IntentService {
app manifest. The following code snippet illustrates how to declare this class as a service:
</p>
<p class="code-caption">
<a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/AndroidManifest.xml" target="_blank">
AndroidManifest.xml</a>
</p>
<pre>
&lt;manifest ... &gt;
&lt;application ... &gt;
...
&lt;service android:name=&quot;.RecommendationsService&quot;
android:enabled=&quot;true&quot; android:exported=&quot;true&quot;/&gt;
&lt;service
android:name="com.example.android.tvleanback.UpdateRecommendationsService"
android:enabled="true" /&gt;
&lt;/application&gt;
&lt;/manifest&gt;
</pre>
<h3 id="refreshing">Refreshing Recommendations</h3>
<p>Base your recommendations on user behavior and data such as play lists, wish lists, and associated
content. When refreshing recommendations, don't just remove and repost them, because doing so causes
the recommendations to appear at the end of the recommendations row. Once a content item, such as a
movie, has been played, <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#Removing">
remove it</a> from the recommendations.</p>
<h2 id="build">Build Recommendations</h2>
<p>
Once your recommendation server starts running, it must create recommendations and pass them to
Once your recommendation service 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:
<h3 id="setting-ui">Setting the Values</h3>
<p>To set the UI element values for the recommendation card, you create a builder class that follows
the builder pattern described as follows. First, you set the values of the recommendation card
elements.</p>
<p class="code-caption">
<a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/java/com/example/android/tvleanback/RecommendationBuilder.java" target="_blank">
RecommendationBuilder.java</a>
</p>
<pre>
public class RecommendationsService extends IntentService {
public class RecommendationBuilder {
...
public Notification buildRecommendation(Context context, Movie movie)
throws IOException {
if (mNotificationManager == null) {
mNotificationManager = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
public RecommendationBuilder setTitle(String title) {
mTitle = title;
return this;
}
Bundle extras = new Bundle();
if (mBackgroundUri != movie.getBackgroundUri()) {
extras.putString(EXTRA_BACKGROUND_IMAGE_URL, movie.getBackgroundUri());
public RecommendationBuilder setDescription(String description) {
mDescription = description;
return this;
}
// build the recommendation as a Notification object
public RecommendationBuilder setImage(String uri) {
mImageUri = uri;
return this;
}
public RecommendationBuilder setBackground(String uri) {
mBackgroundUri = uri;
return this;
}
...
</pre>
<h3 id="create-notification">Creating the Notification</h3>
<p>
Once you've set the values, you then build the notification, assigning the values from the builder
class to the notification, and calling {@link android.support.v4.app.NotificationCompat.Builder#build()
NotificationCompat.Builder.build()}.
</p>
<p>
Also, be sure to call
{@link android.support.v4.app.NotificationCompat.Builder#setLocalOnly(boolean) setLocalOnly()}
so the {@link android.support.v4.app.NotificationCompat.BigPictureStyle} notification won't show up
on other devices.
</p>
<p>
The following code example demonstrates how to build a recommendation, and post it to the manager.
</p>
<p class="code-caption">
<a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/java/com/example/android/tvleanback/RecommendationBuilder.java" target="_blank">
RecommendationBuilder.java</a>
</p>
<pre>
public class RecommendationBuilder {
...
public Notification build() throws IOException {
...
Notification notification = new NotificationCompat.BigPictureStyle(
new NotificationCompat.Builder(context)
.setContentTitle(movie.getTitle())
.setContentText(movie.getDescription())
.setContentInfo(APP_NAME)
.setGroup("ActionMovies")
.setSortKey("0.8")
.setPriority(movie.getPriority())
.setColor(#FFFF2020)
.setCategory("recommendation")
.setLargeIcon(movie.getImage())
.setSmallIcon(movie.getSmallIcon())
.setContentIntent(buildPendingIntent(movie.getId()))
new NotificationCompat.Builder(mContext)
.setContentTitle(mTitle)
.setContentText(mDescription)
.setPriority(mPriority)
.setLocalOnly(true)
.setOngoing(true)
.setColor(mContext.getResources().getColor(R.color.fastlane_background))
.setCategory(Notification.CATEGORY_RECOMMENDATION)
.setLargeIcon(image)
.setSmallIcon(mSmallIcon)
.setContentIntent(mIntent)
.setExtras(extras))
.build();
// post the recommendation to the NotificationManager
mNotificationManager.notify(movie.getId(), notification);
mNotificationManager.notify(mId, notification);
mNotificationManager = null;
return notification;
}
private PendingIntent buildPendingIntent(long id) {
Intent detailsIntent = new Intent(this, DetailsActivity.class);
detailsIntent.putExtra("id", id);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(DetailsActivity.class);
stackBuilder.addNextIntent(detailsIntent);
// Ensure each PendingIntent is unique
detailsIntent.setAction(Long.toString(id));
PendingIntent intent = stackBuilder.getPendingIntent(
0, PendingIntent.FLAG_UPDATE_CURRENT);
return intent;
}
}
</pre>
<h3 id="run-service">Run Recommendations Service</h3>
<h2 id="run-service">Run Recommendations Service</h3>
<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:
every half hour:
</p>
<p class="code-caption">
<a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/java/com/example/android/tvleanback/BootupActivity.java" target="_blank">
BootupActivity.java</a>
</p>
<pre>
public class BootupReceiver extends BroadcastReceiver {
public class BootupActivity extends BroadcastReceiver {
private static final String TAG = "BootupActivity";
private static final long INITIAL_DELAY = 5000;
&#64;Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "BootupActivity initiated");
if (intent.getAction().endsWith(Intent.ACTION_BOOT_COMPLETED)) {
scheduleRecommendationUpdate(context);
}
}
private void scheduleRecommendationUpdate(Context context) {
AlarmManager alarmManager = (AlarmManager)context.getSystemService(
Context.ALARM_SERVICE);
Intent recommendationIntent = new Intent(context,
UpdateRecommendationsService.class);
PendingIntent alarmIntent = PendingIntent.getService(context, 0,
recommendationIntent, 0);
Log.d(TAG, "Scheduling recommendations update");
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent recommendationIntent = new Intent(context, UpdateRecommendationsService.class);
PendingIntent alarmIntent = PendingIntent.getService(context, 0, recommendationIntent, 0);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
INITIAL_DELAY,
AlarmManager.INTERVAL_HALF_DAY,
AlarmManager.INTERVAL_HALF_HOUR,
alarmIntent);
}
}
@@ -221,10 +307,15 @@ public class BootupReceiver extends BroadcastReceiver {
following sample code demonstrates how to add this configuration to the manifest:
</p>
<p class="code-caption">
<a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/AndroidManifest.xml" target="_blank">
AndroidManifest.xml</a>
</p>
<pre>
&lt;manifest ... &gt;
&lt;application ... &gt;
&lt;receiver android:name=&quot;.BootupReceiver&quot; android:enabled=&quot;true&quot;
&lt;receiver android:name=&quot;com.example.android.tvleanback.BootupActivity&quot;
android:enabled=&quot;true&quot;
android:exported=&quot;false&quot;&gt;
&lt;intent-filter&gt;
&lt;action android:name=&quot;android.intent.action.BOOT_COMPLETED&quot;/&gt;
@@ -234,7 +325,7 @@ public class BootupReceiver extends BroadcastReceiver {
&lt;/manifest&gt;
</pre>
<p class="important">
<p class="note">
<strong>Important:</strong> Receiving a boot completed notification requires that your app
requests the {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission.
For more information, see {@link android.content.Intent#ACTION_BOOT_COMPLETED}.