241 lines
8.3 KiB
Plaintext
241 lines
8.3 KiB
Plaintext
page.title=Recommending TV Content
|
|
page.tags="recommendation","recommend"
|
|
|
|
trainingnavtop=true
|
|
|
|
@jd:body
|
|
|
|
<div id="tb-wrapper">
|
|
<div id="tb">
|
|
<h2>This lesson teaches you to</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>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
|
|
<p>
|
|
When interacting with TVs, users generally prefer to give minimal input before watching
|
|
content. An ideal scenario for many TV users is: sit down, turn on, and watch. The fewest steps
|
|
to get users to content they enjoy is generally the path they prefer.
|
|
</p>
|
|
|
|
<p>
|
|
The Android framework assists with minimum-input interaction by providing a recommendations row
|
|
on the home screen. Content recommendations appear as the first row of the TV launch screen after
|
|
the first use of the device. Contributing recommendations from your app's content catalog can help
|
|
bring users back to your app.
|
|
</p>
|
|
|
|
<img src="{@docRoot}preview/tv/images/home-recommendations.png" alt="" id="figure1" />
|
|
<p class="img-caption">
|
|
<strong>Figure 1.</strong> An example of the recommendations row.
|
|
</p>
|
|
|
|
<p>
|
|
This lesson teaches you how to create recommendations and provide them to the Android framework
|
|
so your app content can be easily discovered and enjoyed by users.
|
|
</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, 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 {@link android.app.IntentService} to
|
|
create a recommendation service for your application:
|
|
</p>
|
|
|
|
<pre>
|
|
public class RecommendationsService extends IntentService {
|
|
private static final int MAX_RECOMMENDATIONS = 3;
|
|
|
|
public RecommendationsService() {
|
|
super("RecommendationService");
|
|
}
|
|
|
|
@Override
|
|
protected void onHandleIntent(Intent intent) {
|
|
MovieDatabase database = MovieDatabase.instance(getApplicationContext());
|
|
List<Movie> recommendations = database.recommendations();
|
|
|
|
int count = 0;
|
|
|
|
try {
|
|
for (Movie movie : recommendations) {
|
|
// build the individual content recommendations
|
|
buildRecommendation(getApplicationContext(), movie);
|
|
|
|
if (++count >= MAX_RECOMMENDATIONS) {
|
|
break;
|
|
}
|
|
}
|
|
} catch (IOException e) {
|
|
Log.e(TAG, "Unable to update recommendation", e);
|
|
}
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<p>
|
|
In order for this service to be recognized by the system and run, register it using your
|
|
app manifest. The following code snippet illustrates how to declare this class as a service:
|
|
</p>
|
|
|
|
<pre>
|
|
<manifest ... >
|
|
<application ... >
|
|
...
|
|
|
|
<service android:name=".RecommendationsService"
|
|
android:enabled="true" android:exported="true"/>
|
|
</application>
|
|
</manifest>
|
|
</pre>
|
|
|
|
|
|
<h2 id="build">Build Recommendations</h2>
|
|
|
|
<p>
|
|
Once your recommendation server starts running, it 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 template 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())
|
|
.setContentInfo(APP_NAME)
|
|
.setGroup("ActionMovies")
|
|
.setSortKey("0.8")
|
|
.setPriority(movie.getPriority())
|
|
.setColor(#FFFF2020)
|
|
.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. To run your service, 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 12 hours:
|
|
</p>
|
|
|
|
<pre>
|
|
public class BootupReceiver 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_DAY,
|
|
alarmIntent);
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<p>
|
|
This implementation of the {@link android.content.BroadcastReceiver} class must run after start
|
|
up of the TV device where it is installed. To accomplish this, register this class in your app
|
|
manifest with an intent filter that listens for the completion of the device boot process. The
|
|
following sample code demonstrates how to add this configuration to the manifest:
|
|
</p>
|
|
|
|
<pre>
|
|
<manifest ... >
|
|
<application ... >
|
|
<receiver android:name=".BootupReceiver" android:enabled="true"
|
|
android:exported="false">
|
|
<intent-filter>
|
|
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
|
</intent-filter>
|
|
</receiver>
|
|
</application>
|
|
</manifest>
|
|
</pre>
|
|
|
|
<p class="important">
|
|
<strong>Important:</strong> Receiving a boot completed notification requires that your app
|
|
requests the {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission.
|
|
For more information, see {@link android.content.Intent#ACTION_BOOT_COMPLETED}.
|
|
</p>
|