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