1page.title=Recommending TV Content 2page.tags=tv, recommendations 3helpoutsWidget=true 4 5trainingnavtop=true 6 7@jd:body 8 9<div id="tb-wrapper"> 10<div id="tb"> 11 <h2>This lesson teaches you to</h2> 12 <ol> 13 <li><a href="#best-practices">Best Practices for Recommendations</a></li> 14 <li><a href="#service">Create a Recommendations Service</a></li> 15 <li><a href="#build">Build Recommendations</a></li> 16 <li><a href="#run-service">Run Recommendations Service</a></li> 17 </ol> 18 <h2>Try it out</h2> 19 <ul> 20 <li><a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android 21 Leanback sample app</a></li> 22 </ul> 23</div> 24</div> 25 26<p> 27 When interacting with TVs, users generally prefer to give minimal input before watching 28 content. An ideal scenario for many TV users is: sit down, turn on, and watch. The fewest steps 29 to get users to content they enjoy is generally the path they prefer. 30</p> 31 32<p> 33 The Android framework assists with minimum-input interaction by providing a recommendations row 34 on the home screen. Content recommendations appear as the first row of the TV home screen after 35 the first use of the device. Contributing recommendations from your app's content catalog can help 36 bring users back to your app. 37</p> 38 39<img src="{@docRoot}images/tv/home-recommendations.png" alt="" id="figure1" /> 40<p class="img-caption"> 41 <strong>Figure 1.</strong> An example of the recommendations row. 42</p> 43 44<p> 45 This lesson teaches you how to create recommendations and provide them to the Android framework 46 so users can easily discover and enjoy your app content. This discussion describes some code from 47 the <a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android 48 Leanback sample app</a>. 49</p> 50 51<h2 id="best-practices">Best Practices for Recommendations</h2> 52 53<p>Recommendations help users quickly find the content and apps they enjoy. Creating 54recommendations that are high-quality and relevant to users is an important factor in creating a 55great user experience with your TV app. For this reason, you should carefully consider what 56recommendations you present to the user and manage them closely.</p> 57 58<h3 id="types">Types of Recommendations</h3> 59 60<p>When you create recommendations, you should link users back to incomplete viewing activities or 61suggest activities that extend that to related content. Here are some specific type of 62recommendations you should consider:</p> 63 64<ul> 65<li><strong>Continuation content</strong> recommendations for the next episode for users to resume 66watching a series.</li> 67<li><strong>New content</strong> recommendations, such as for a new first-run episode, if the user 68finished watching another series. 69<li><strong>Related content</strong> recommendations based on the users historic viewing behavior. 70</ul> 71 72<p>For more information on how to design recommendation cards for the best user experience, see 73<a href="https://www.google.com/design/spec-tv/system-overview/recommendation-row.html#recommendation-row-types-of-recommendations" 74class="external-link">Recommendation Row</a> in the Android TV Design Spec.</p> 75 76<h3 id="refreshing">Refreshing Recommendations</h3> 77 78<p>When refreshing recommendations, don't just remove and repost them, because doing so causes 79the recommendations to appear at the end of the recommendations row. Once a content item, such as a 80movie, has been played, <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#Removing"> 81remove it</a> from the recommendations.</p> 82 83<h3 id="customization">Customizing Recommendations</h3> 84 85<p>You can customize recommendation cards to convey branding information, by setting user interface 86elements such as the card's foreground and background image, color, app icon, title, and subtitle. 87To learn more, see 88<a href="https://www.google.com/design/spec-tv/system-overview/recommendation-row.html#recommendation-row-card-customization" 89class="external-link">Recommendation Row</a> in the Android TV Design Spec.</p> 90 91 92<h2 id="service">Create a Recommendations Service</h2> 93 94<p> 95 Content recommendations are created with background processing. In order for your application to 96 contribute to recommendations, create a service that periodically adds listings from your 97 app's catalog to the system's list of recommendations. 98</p> 99 100<p> 101 The following code example illustrates how to extend {@link android.app.IntentService} to 102 create a recommendation service for your application: 103</p> 104 105<pre> 106public class UpdateRecommendationsService extends IntentService { 107 private static final String TAG = "UpdateRecommendationsService"; 108 private static final int MAX_RECOMMENDATIONS = 3; 109 110 public UpdateRecommendationsService() { 111 super("RecommendationService"); 112 } 113 114 @Override 115 protected void onHandleIntent(Intent intent) { 116 Log.d(TAG, "Updating recommendation cards"); 117 HashMap<String, List<Movie>> recommendations = VideoProvider.getMovieList(); 118 if (recommendations == null) return; 119 120 int count = 0; 121 122 try { 123 RecommendationBuilder builder = new RecommendationBuilder() 124 .setContext(getApplicationContext()) 125 .setSmallIcon(R.drawable.videos_by_google_icon); 126 127 for (Map.Entry<String, List<Movie>> entry : recommendations.entrySet()) { 128 for (Movie movie : entry.getValue()) { 129 Log.d(TAG, "Recommendation - " + movie.getTitle()); 130 131 builder.setBackground(movie.getCardImageUrl()) 132 .setId(count + 1) 133 .setPriority(MAX_RECOMMENDATIONS - count) 134 .setTitle(movie.getTitle()) 135 .setDescription(getString(R.string.popular_header)) 136 .setImage(movie.getCardImageUrl()) 137 .setIntent(buildPendingIntent(movie)) 138 .build(); 139 140 if (++count >= MAX_RECOMMENDATIONS) { 141 break; 142 } 143 } 144 if (++count >= MAX_RECOMMENDATIONS) { 145 break; 146 } 147 } 148 } catch (IOException e) { 149 Log.e(TAG, "Unable to update recommendation", e); 150 } 151 } 152 153 private PendingIntent buildPendingIntent(Movie movie) { 154 Intent detailsIntent = new Intent(this, DetailsActivity.class); 155 detailsIntent.putExtra("Movie", movie); 156 157 TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); 158 stackBuilder.addParentStack(DetailsActivity.class); 159 stackBuilder.addNextIntent(detailsIntent); 160 // Ensure a unique PendingIntents, otherwise all 161 // recommendations end up with the same PendingIntent 162 detailsIntent.setAction(Long.toString(movie.getId())); 163 164 PendingIntent intent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); 165 return intent; 166 } 167} 168</pre> 169 170<p> 171 In order for this service to be recognized by the system and run, register it using your 172 app manifest. The following code snippet illustrates how to declare this class as a service: 173</p> 174 175<pre> 176<manifest ... > 177 <application ... > 178 ... 179 180 <service 181 android:name="com.example.android.tvleanback.UpdateRecommendationsService" 182 android:enabled="true" /> 183 </application> 184</manifest> 185</pre> 186 187<h2 id="build">Build Recommendations</h2> 188 189<p> 190 Once your recommendation service starts running, it must create recommendations and pass them to 191 the Android framework. The framework receives the recommendations as {@link 192 android.app.Notification} objects that use a specific template and are marked with a specific 193 category. 194</p> 195 196<h3 id="setting-ui">Setting the Values</h3> 197 198<p>To set the UI element values for the recommendation card, you create a builder class that follows 199the builder pattern described as follows. First, you set the values of the recommendation card 200elements.</p> 201 202<pre> 203public class RecommendationBuilder { 204 ... 205 206 public RecommendationBuilder setTitle(String title) { 207 mTitle = title; 208 return this; 209 } 210 211 public RecommendationBuilder setDescription(String description) { 212 mDescription = description; 213 return this; 214 } 215 216 public RecommendationBuilder setImage(String uri) { 217 mImageUri = uri; 218 return this; 219 } 220 221 public RecommendationBuilder setBackground(String uri) { 222 mBackgroundUri = uri; 223 return this; 224 } 225... 226</pre> 227 228<h3 id="create-notification">Creating the Notification</h3> 229 230<p> 231 Once you've set the values, you then build the notification, assigning the values from the builder 232 class to the notification, and calling {@link android.support.v4.app.NotificationCompat.Builder#build() 233 NotificationCompat.Builder.build()}. 234</p> 235 236<p> 237 Also, be sure to call 238 {@link android.support.v4.app.NotificationCompat.Builder#setLocalOnly(boolean) setLocalOnly()} 239 so the {@link android.support.v4.app.NotificationCompat.BigPictureStyle} notification won't show up 240 on other devices. 241</p> 242 243<p> 244 The following code example demonstrates how to build a recommendation. 245</p> 246 247<pre> 248public class RecommendationBuilder { 249 ... 250 251 public Notification build() throws IOException { 252 ... 253 254 Notification notification = new NotificationCompat.BigPictureStyle( 255 new NotificationCompat.Builder(mContext) 256 .setContentTitle(mTitle) 257 .setContentText(mDescription) 258 .setPriority(mPriority) 259 .setLocalOnly(true) 260 .setOngoing(true) 261 .setColor(mContext.getResources().getColor(R.color.fastlane_background)) 262 .setCategory(Notification.CATEGORY_RECOMMENDATION) 263 .setLargeIcon(image) 264 .setSmallIcon(mSmallIcon) 265 .setContentIntent(mIntent) 266 .setExtras(extras)) 267 .build(); 268 269 return notification; 270 } 271} 272</pre> 273 274<h2 id="run-service">Run Recommendations Service</h3> 275 276<p> 277 Your app's recommendation service must run periodically in order to create current 278 recommendations. To run your service, create a class that runs a timer and invokes 279 it at regular intervals. The following code example extends the {@link 280 android.content.BroadcastReceiver} class to start periodic execution of a recommendation service 281 every half hour: 282</p> 283 284<pre> 285public class BootupActivity extends BroadcastReceiver { 286 private static final String TAG = "BootupActivity"; 287 288 private static final long INITIAL_DELAY = 5000; 289 290 @Override 291 public void onReceive(Context context, Intent intent) { 292 Log.d(TAG, "BootupActivity initiated"); 293 if (intent.getAction().endsWith(Intent.ACTION_BOOT_COMPLETED)) { 294 scheduleRecommendationUpdate(context); 295 } 296 } 297 298 private void scheduleRecommendationUpdate(Context context) { 299 Log.d(TAG, "Scheduling recommendations update"); 300 301 AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 302 Intent recommendationIntent = new Intent(context, UpdateRecommendationsService.class); 303 PendingIntent alarmIntent = PendingIntent.getService(context, 0, recommendationIntent, 0); 304 305 alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 306 INITIAL_DELAY, 307 AlarmManager.INTERVAL_HALF_HOUR, 308 alarmIntent); 309 } 310} 311</pre> 312 313<p> 314 This implementation of the {@link android.content.BroadcastReceiver} class must run after start 315 up of the TV device where it is installed. To accomplish this, register this class in your app 316 manifest with an intent filter that listens for the completion of the device boot process. The 317 following sample code demonstrates how to add this configuration to the manifest: 318</p> 319 320<pre> 321<manifest ... > 322 <application ... > 323 <receiver android:name="com.example.android.tvleanback.BootupActivity" 324 android:enabled="true" 325 android:exported="false"> 326 <intent-filter> 327 <action android:name="android.intent.action.BOOT_COMPLETED"/> 328 </intent-filter> 329 </receiver> 330 </application> 331</manifest> 332</pre> 333 334<p class="note"> 335 <strong>Important:</strong> Receiving a boot completed notification requires that your app 336 requests the {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission. 337 For more information, see {@link android.content.Intent#ACTION_BOOT_COMPLETED}. 338</p> 339 340<p>In your recommendation service class' {@link android.app.IntentService#onHandleIntent(android.content.Intent) 341onHandleIntent()} 342method, post the recommendation to the manager as follows:</p> 343 344<pre> 345Notification notification = notificationBuilder.build(); 346mNotificationManager.notify(id, notification); 347</pre> 348