1page.title=Recommending TV Content 2page.tags="recommendation","recommend" 3 4trainingnavtop=true 5 6@jd:body 7 8<div id="tb-wrapper"> 9<div id="tb"> 10 <h2>This lesson teaches you to</h2> 11 <ol> 12 <li><a href="#service">Create a Recommendations Service</a></li> 13 <li><a href="#build">Build Recommendations</a></li> 14 <li><a href="#run-service">Run Recommendations Service</a></li> 15 </ol> 16</div> 17</div> 18 19<p> 20 When interacting with TVs, users generally prefer to give minimal input before watching 21 content. An ideal scenario for many TV users is: sit down, turn on, and watch. The fewest steps 22 to get users to content they enjoy is generally the path they prefer. 23</p> 24 25<p> 26 The Android framework assists with minimum-input interaction by providing a recommendations row 27 on the home screen. Content recommendations appear as the first row of the TV launch screen after 28 the first use of the device. Contributing recommendations from your app's content catalog can help 29 bring users back to your app. 30</p> 31 32<img src="{@docRoot}images/tv/home-recommendations.png" alt="" id="figure1" /> 33<p class="img-caption"> 34 <strong>Figure 1.</strong> An example of the recommendations row. 35</p> 36 37<p> 38 This lesson teaches you how to create recommendations and provide them to the Android framework 39 so your app content can be easily discovered and enjoyed by users. 40</p> 41 42 43<h2 id="service">Create a Recommendations Service</h2> 44 45<p> 46 Content recommendations are created with background processing. In order for your application to 47 contribute to recommendations, create a service that periodically adds listings from your 48 app's catalog to the system list of recommendations. 49</p> 50 51<p> 52 The following code example illustrates how to extend {@link android.app.IntentService} to 53 create a recommendation service for your application: 54</p> 55 56<pre> 57public class RecommendationsService extends IntentService { 58 private static final int MAX_RECOMMENDATIONS = 3; 59 60 public RecommendationsService() { 61 super("RecommendationService"); 62 } 63 64 @Override 65 protected void onHandleIntent(Intent intent) { 66 MovieDatabase database = MovieDatabase.instance(getApplicationContext()); 67 List<Movie> recommendations = database.recommendations(); 68 69 int count = 0; 70 71 try { 72 for (Movie movie : recommendations) { 73 // build the individual content recommendations 74 buildRecommendation(getApplicationContext(), movie); 75 76 if (++count >= MAX_RECOMMENDATIONS) { 77 break; 78 } 79 } 80 } catch (IOException e) { 81 Log.e(TAG, "Unable to update recommendation", e); 82 } 83 } 84} 85</pre> 86 87<p> 88 In order for this service to be recognized by the system and run, register it using your 89 app manifest. The following code snippet illustrates how to declare this class as a service: 90</p> 91 92<pre> 93<manifest ... > 94 <application ... > 95 ... 96 97 <service android:name=".RecommendationsService" 98 android:enabled="true" android:exported="true"/> 99 </application> 100</manifest> 101</pre> 102 103 104<h2 id="build">Build Recommendations</h2> 105 106<p> 107 Once your recommendation server starts running, it must create recommendations and pass them to 108 the Android framework. The framework receives the recommendations as {@link 109 android.app.Notification} objects that use a specific template and are marked with a specific 110 category. 111</p> 112 113<p> 114 The following code example demonstrates how to get an instance of the {@link 115 android.app.NotificationManager}, build a recommendation, and post it to the manager: 116</p> 117 118<pre> 119public class RecommendationsService extends IntentService { 120 121 ... 122 123 public Notification buildRecommendation(Context context, Movie movie) 124 throws IOException { 125 126 if (mNotificationManager == null) { 127 mNotificationManager = (NotificationManager) 128 mContext.getSystemService(Context.NOTIFICATION_SERVICE); 129 } 130 131 Bundle extras = new Bundle(); 132 if (mBackgroundUri != movie.getBackgroundUri()) { 133 extras.putString(EXTRA_BACKGROUND_IMAGE_URL, movie.getBackgroundUri()); 134 } 135 136 // build the recommendation as a Notification object 137 Notification notification = new NotificationCompat.BigPictureStyle( 138 new NotificationCompat.Builder(context) 139 .setContentTitle(movie.getTitle()) 140 .setContentText(movie.getDescription()) 141 .setContentInfo(APP_NAME) 142 .setGroup("ActionMovies") 143 .setSortKey("0.8") 144 .setPriority(movie.getPriority()) 145 .setColor(#FFFF2020) 146 .setCategory("recommendation") 147 .setLargeIcon(movie.getImage()) 148 .setSmallIcon(movie.getSmallIcon()) 149 .setContentIntent(buildPendingIntent(movie.getId())) 150 .setExtras(extras)) 151 .build(); 152 153 // post the recommendation to the NotificationManager 154 mNotificationManager.notify(movie.getId(), notification); 155 mNotificationManager = null; 156 return notification; 157 } 158 159 private PendingIntent buildPendingIntent(long id) { 160 Intent detailsIntent = new Intent(this, DetailsActivity.class); 161 detailsIntent.putExtra("id", id); 162 163 TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); 164 stackBuilder.addParentStack(DetailsActivity.class); 165 stackBuilder.addNextIntent(detailsIntent); 166 // Ensure each PendingIntent is unique 167 detailsIntent.setAction(Long.toString(id)); 168 169 PendingIntent intent = stackBuilder.getPendingIntent( 170 0, PendingIntent.FLAG_UPDATE_CURRENT); 171 return intent; 172 } 173} 174</pre> 175 176 177<h3 id="run-service">Run Recommendations Service</h3> 178 179<p> 180 Your app's recommendation service must run periodically in order to create current 181 recommendations. To run your service, create a class that runs a timer and invokes 182 it at regular intervals. The following code example extends the {@link 183 android.content.BroadcastReceiver} class to start periodic execution of a recommendation service 184 every 12 hours: 185</p> 186 187<pre> 188public class BootupReceiver extends BroadcastReceiver { 189 private static final String TAG = "BootupActivity"; 190 191 private static final long INITIAL_DELAY = 5000; 192 193 @Override 194 public void onReceive(Context context, Intent intent) { 195 if (intent.getAction().endsWith(Intent.ACTION_BOOT_COMPLETED)) { 196 scheduleRecommendationUpdate(context); 197 } 198 } 199 200 private void scheduleRecommendationUpdate(Context context) { 201 AlarmManager alarmManager = (AlarmManager)context.getSystemService( 202 Context.ALARM_SERVICE); 203 Intent recommendationIntent = new Intent(context, 204 UpdateRecommendationsService.class); 205 PendingIntent alarmIntent = PendingIntent.getService(context, 0, 206 recommendationIntent, 0); 207 208 alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 209 INITIAL_DELAY, 210 AlarmManager.INTERVAL_HALF_DAY, 211 alarmIntent); 212 } 213} 214</pre> 215 216<p> 217 This implementation of the {@link android.content.BroadcastReceiver} class must run after start 218 up of the TV device where it is installed. To accomplish this, register this class in your app 219 manifest with an intent filter that listens for the completion of the device boot process. The 220 following sample code demonstrates how to add this configuration to the manifest: 221</p> 222 223<pre> 224<manifest ... > 225 <application ... > 226 <receiver android:name=".BootupReceiver" android:enabled="true" 227 android:exported="false"> 228 <intent-filter> 229 <action android:name="android.intent.action.BOOT_COMPLETED"/> 230 </intent-filter> 231 </receiver> 232 </application> 233</manifest> 234</pre> 235 236<p class="important"> 237 <strong>Important:</strong> Receiving a boot completed notification requires that your app 238 requests the {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission. 239 For more information, see {@link android.content.Intent#ACTION_BOOT_COMPLETED}. 240</p> 241