| page.title=Making Recommendations |
| parent.title=User Interfaces for TV |
| parent.link=index.html |
| |
| trainingnavtop=true |
| previous.title=Searching in TV Apps |
| previous.link=in-app-search.html |
| |
| @jd:body |
| |
| <div id="qv-wrapper"> |
| <div id="qv"> |
| <h2>In this document</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> |
| <li><a href="#DesignLandscapeLayouts">Design Landscape Layouts</a></li> |
| </ol> |
| |
| </div> |
| </div> |
| |
| |
| <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> |
| |
| |
| <img src="{@docRoot}preview/tv/images/home-recommendations.png" alt="" height="XXX" id="figure1" /> |
| <p class="img-caption"> |
| <strong>Figure 1.</strong> The first row after the search widget is the system-wide |
| recommendations. |
| </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>The following code example illustrates how to extend the {@link android.app.IntentService} to |
| create a recommendation service for your application.</p> |
| |
| <pre> |
| public class RecommendationsService extends IntentService { |
| |
| ... |
| |
| public Notification buildRecommendation(Context context, Movie movie) |
| throws IOException { |
| |
| if (mNotificationManager == null) { |
| mNotificationManager = (NotificationManager) |
| mContext.getSystemService(Context.NOTIFICATION_SERVICE); |
| } |
| |
| Bundle extras = new Bundle(); |
| if (mBackgroundUri != movie.getBackgroundUri()) { |
| extras.putString(EXTRA_BACKGROUND_IMAGE_URL, movie.getBackgroundUri()); |
| } |
| |
| // build the recommendation as a Notification object |
| Notification notification = new NotificationCompat.BigPictureStyle( |
| new NotificationCompat.Builder(context) |
| .setContentTitle(movie.getTitle()) |
| .setContentText(movie.getDescription()) |
| .setPriority(movie.getPriority()) |
| .setOngoing(true) |
| .setCategory("recommendation") |
| .setLargeIcon(movie.getImage()) |
| .setSmallIcon(movie.getSmallIcon()) |
| .setContentIntent(buildPendingIntent(movie.getId())) |
| .setExtras(extras)) |
| .build(); |
| |
| // post the recommendation to the NotificationManager |
| mNotificationManager.notify(movie.getId(), 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> |
| |
| <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> |
| |
| <pre> |
| <manifest ... > |
| <application ... > |
| ... |
| |
| <service android:name=".UpdateRecommendationsService" |
| android:enabled="true" android:exported="true"/> |
| </application> |
| </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>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 { |
| |
| ... |
| |
| public Notification buildRecommendation(Context context, Movie movie) |
| throws IOException { |
| |
| if (mNotificationManager == null) { |
| mNotificationManager = (NotificationManager) |
| mContext.getSystemService(Context.NOTIFICATION_SERVICE); |
| } |
| |
| Bundle extras = new Bundle(); |
| if (mBackgroundUri != movie.getBackgroundUri()) { |
| extras.putString(EXTRA_BACKGROUND_IMAGE_URL, movie.getBackgroundUri()); |
| } |
| |
| // build the recommendation as a Notification object |
| Notification notification = new NotificationCompat.BigPictureStyle( |
| new NotificationCompat.Builder(context) |
| .setContentTitle(movie.getTitle()) |
| .setContentText(movie.getDescription()) |
| .setPriority(movie.getPriority()) |
| .setOngoing(true) |
| .setCategory("recommendation") |
| .setLargeIcon(movie.getImage()) |
| .setSmallIcon(movie.getSmallIcon()) |
| .setContentIntent(buildPendingIntent(movie.getId())) |
| .setExtras(extras)) |
| .build(); |
| |
| // post the recommendation to the NotificationManager |
| mNotificationManager.notify(movie.getId(), 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> |
| |
| <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 |
| android.content.BroadcastReceiver} class to start periodic execution of a recommendation service |
| every 30 minutes:</p> |
| |
| <pre> |
| public class BootupActivity extends BroadcastReceiver { |
| private static final String TAG = "BootupActivity"; |
| |
| private static final long INITIAL_DELAY = 5000; |
| |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| 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); |
| |
| alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, |
| INITIAL_DELAY, |
| AlarmManager.INTERVAL_HALF_HOUR, |
| alarmIntent); |
| } |
| } |
| </pre> |
| |
| <p>In order for the {@link android.content.BroadcastReceiver} class to execute after an TV |
| device starts up, you must register this class in your app manifest and attach an intent filter |
| for the completion of the device boot process. This sample code demonstrates how to add this |
| configuration to the manifest:</p> |
| |
| <pre> |
| <manifest ... > |
| <application ... > |
| <receiver android:name=".BootupActivity" android:enabled="true" |
| android:exported="false"> |
| <intent-filter> |
| <action android:name="android.intent.action.BOOT_COMPLETED"/> |
| </intent-filter> |
| </receiver> |
| </application> |
| </manifest> |
| </pre> |