page.title=Recommending TV Content page.tags="recommendation","recommend" trainingnavtop=true @jd:body
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.
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.
Figure 1. An example of the recommendations row.
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.
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.
The following code example illustrates how to extend {@link android.app.IntentService} to create a recommendation service for your application:
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()); Listrecommendations = 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); } } }
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:
<manifest ... > <application ... > ... <service android:name=".RecommendationsService" android:enabled="true" android:exported="true"/> </application> </manifest>
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.
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:
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; } }
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:
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); } }
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:
<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>
Important: 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}.