• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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    &#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&lt;manifest ... &gt;
94  &lt;application ... &gt;
95    ...
96
97    &lt;service android:name=&quot;.RecommendationsService&quot;
98             android:enabled=&quot;true&quot; android:exported=&quot;true&quot;/&gt;
99  &lt;/application&gt;
100&lt;/manifest&gt;
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    &#64;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&lt;manifest ... &gt;
225  &lt;application ... &gt;
226    &lt;receiver android:name=&quot;.BootupReceiver&quot; android:enabled=&quot;true&quot;
227              android:exported=&quot;false&quot;&gt;
228      &lt;intent-filter&gt;
229        &lt;action android:name=&quot;android.intent.action.BOOT_COMPLETED&quot;/&gt;
230      &lt;/intent-filter&gt;
231    &lt;/receiver&gt;
232  &lt;/application&gt;
233&lt;/manifest&gt;
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