summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorJoe Fernandez <joefernandez@google.com>2014-12-20 00:30:07 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-12-20 00:30:09 +0000
commit7cec35ef5225f3dbc11cd78b96478751fe4158c3 (patch)
tree686ae28ef38b6199b4c3cb648659938c802f61e0 /docs
parenta9a36ab225f8e53d79d83ff9eb452efc4933b6ae (diff)
parentea7a71b25d9d89dccc823df530dceb389a145cda (diff)
downloadframeworks_base-7cec35ef5225f3dbc11cd78b96478751fe4158c3.zip
frameworks_base-7cec35ef5225f3dbc11cd78b96478751fe4158c3.tar.gz
frameworks_base-7cec35ef5225f3dbc11cd78b96478751fe4158c3.tar.bz2
Merge "docs: b/18122848 [DAC] Android TV - Recommendation card" into lmp-docs
Diffstat (limited to 'docs')
-rw-r--r--docs/html/design/tv/index.jd2
-rw-r--r--docs/html/design/tv/patterns.jd112
-rw-r--r--docs/html/images/tv/recommend-card.pngbin0 -> 105512 bytes
-rw-r--r--docs/html/training/tv/discovery/recommendations.jd233
4 files changed, 241 insertions, 106 deletions
diff --git a/docs/html/design/tv/index.jd b/docs/html/design/tv/index.jd
index d79e279..def1286 100644
--- a/docs/html/design/tv/index.jd
+++ b/docs/html/design/tv/index.jd
@@ -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
diff --git a/docs/html/design/tv/patterns.jd b/docs/html/design/tv/patterns.jd
index be7ae31..e786ee5 100644
--- a/docs/html/design/tv/patterns.jd
+++ b/docs/html/design/tv/patterns.jd
@@ -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>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>
-<p>Here are the requirements for recommendation icons:</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
diff --git a/docs/html/images/tv/recommend-card.png b/docs/html/images/tv/recommend-card.png
new file mode 100644
index 0000000..1cc4311
--- /dev/null
+++ b/docs/html/images/tv/recommend-card.png
Binary files differ
diff --git a/docs/html/training/tv/discovery/recommendations.jd b/docs/html/training/tv/discovery/recommendations.jd
index 0f6d256..d348c14 100644
--- a/docs/html/training/tv/discovery/recommendations.jd
+++ b/docs/html/training/tv/discovery/recommendations.jd
@@ -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:
-</p>
+<h3 id="setting-ui">Setting the Values</h3>
-<pre>
-public class RecommendationsService extends IntentService {
+<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 RecommendationBuilder {
...
- public Notification buildRecommendation(Context context, Movie movie)
- throws IOException {
+ public RecommendationBuilder setTitle(String title) {
+ mTitle = title;
+ return this;
+ }
+
+ public RecommendationBuilder setDescription(String description) {
+ mDescription = description;
+ return this;
+ }
- if (mNotificationManager == null) {
- mNotificationManager = (NotificationManager)
- mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ public RecommendationBuilder setImage(String uri) {
+ mImageUri = uri;
+ return this;
}
- Bundle extras = new Bundle();
- if (mBackgroundUri != movie.getBackgroundUri()) {
- extras.putString(EXTRA_BACKGROUND_IMAGE_URL, movie.getBackgroundUri());
+ 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 {
+ ...
- // build the recommendation as a Notification object
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}.