Recommandations dans Android N et les versions antérieures

Lorsqu'ils interagissent avec les téléviseurs, les utilisateurs préfèrent généralement donner le moins d'informations avant de regarder du contenu. Pour de nombreux utilisateurs de téléviseurs, le scénario idéal est le suivant: asseyez-vous, allumez votre téléviseur et regardez le film. En règle générale, la procédure la plus simple pour rediriger les utilisateurs vers le contenu qu'ils apprécient est celle qu'ils préfèrent.

Remarque:Utilisez les API décrites ici pour faire des recommandations dans les applications exécutées sur des versions d'Android allant jusqu'à Android 7.1 (niveau d'API 25) inclus. Afin de fournir des recommandations pour les applications exécutées sous Android 8.0 (niveau d'API 26) ou version ultérieure, votre application doit utiliser des canaux de recommandation.

Le framework Android contribue à limiter l'interaction en entrée en fournissant une ligne de recommandations sur l'écran d'accueil. Les recommandations de contenu apparaissent sur la première ligne de l'écran d'accueil du téléviseur après la première utilisation de l'appareil. Les recommandations issues du catalogue de contenus de votre application peuvent inciter les utilisateurs à revenir dans votre application.

Figure 1 : Exemple de ligne de recommandations.

Ce guide vous explique comment créer des recommandations et les fournir au framework Android afin que les utilisateurs puissent facilement découvrir et apprécier le contenu de votre application. Consultez également l'exemple d'implémentation dans l' application exemple Leanback.

Bonnes pratiques concernant les recommandations

Les recommandations aident les utilisateurs à trouver rapidement le contenu et les applications qu'ils apprécient. La création de recommandations de haute qualité et pertinentes pour les utilisateurs est un facteur important pour créer une expérience utilisateur optimale avec votre application TV. C'est pourquoi vous devez soigneusement réfléchir aux recommandations que vous présentez à l'utilisateur et les gérer de près.

Types de recommandations

Lorsque vous créez des recommandations, vous devez rediriger les utilisateurs vers des activités de visionnage incomplètes ou leur suggérer des activités qui s'appliquent à des contenus associés. Voici quelques recommandations spécifiques à prendre en compte:

  • Recommandations de contenu de continuation pour l'épisode suivant afin que les utilisateurs puissent reprendre la lecture d'une série. Vous pouvez également utiliser les recommandations de continuation pour les films, séries TV ou podcasts mis en pause, afin que les utilisateurs puissent reprendre leur visionnage en quelques clics.
  • Recommandations de nouveaux contenus, par exemple pour un nouvel épisode diffusé en avant-première si l'utilisateur a fini de regarder une autre série. De plus, si votre application permet aux utilisateurs de s'abonner à du contenu, de le suivre ou de le suivre, utilisez de nouvelles recommandations de contenu pour les éléments non regardés dans leur liste de contenus suivis.
  • des recommandations de contenus associés basées sur l'historique du comportement de visionnage des utilisateurs ;

Pour en savoir plus sur la conception de fiches de recommandations afin d'optimiser l'expérience utilisateur, consultez Ligne de recommandations dans les spécifications de conception d'Android TV.

Actualiser les recommandations

Lorsque vous actualisez des recommandations, ne vous contentez pas de les supprimer et de les republier, car cela entraîne leur affichage à la fin de la ligne des recommandations. Une fois qu'un élément de contenu, tel qu'un film, a été lu, supprimez-le des recommandations.

Personnaliser les recommandations

Vous pouvez personnaliser les fiches de recommandation pour transmettre des informations de branding, en définissant des éléments d'interface utilisateur tels que l'image de premier plan et de fond, la couleur, l'icône de l'application, le titre et le sous-titre. Pour en savoir plus, consultez Ligne de recommandation dans les spécifications de conception d'Android TV.

Recommandations de groupes

Vous pouvez éventuellement regrouper les recommandations en fonction de leur source. Par exemple, votre application peut fournir deux groupes de recommandations: des recommandations de contenus auxquels l'utilisateur est abonné et des recommandations de nouveaux contenus tendance dont l'utilisateur n'a peut-être pas connaissance.

Le système classe et classe les recommandations pour chaque groupe séparément lors de la création ou de la mise à jour de la ligne de recommandations. En fournissant des informations de groupe pour vos recommandations, vous pouvez vous assurer qu'elles ne s'affichent pas en dessous de celles sans rapport avec la vôtre.

Utilisez NotificationCompat.Builder.setGroup() pour définir la chaîne de clé de groupe d'une recommandation. Par exemple, pour marquer une recommandation comme appartenant à un groupe qui contient de nouveaux contenus tendance, vous pouvez appeler setGroup("trending").

Créer un service de recommandations

Les recommandations de contenu sont créées avec un traitement en arrière-plan. Pour que votre application contribue aux recommandations, créez un service qui ajoute régulièrement des listes du catalogue de votre application à la liste de recommandations du système.

L'exemple de code suivant montre comment étendre IntentService afin de créer un service de recommandation pour votre application:

Kotlin

class UpdateRecommendationsService : IntentService("RecommendationService") {
    override protected fun onHandleIntent(intent: Intent) {
        Log.d(TAG, "Updating recommendation cards")
        val recommendations = VideoProvider.getMovieList()
        if (recommendations == null) return

        var count = 0

        try {
            val builder = RecommendationBuilder()
                    .setContext(applicationContext)
                    .setSmallIcon(R.drawable.videos_by_google_icon)

            for (entry in recommendations.entrySet()) {
                for (movie in entry.getValue()) {
                    Log.d(TAG, "Recommendation - " + movie.getTitle())

                    builder.setBackground(movie.getCardImageUrl())
                            .setId(count + 1)
                            .setPriority(MAX_RECOMMENDATIONS - count)
                            .setTitle(movie.getTitle())
                            .setDescription(getString(R.string.popular_header))
                            .setImage(movie.getCardImageUrl())
                            .setIntent(buildPendingIntent(movie))
                            .build()
                    if (++count >= MAX_RECOMMENDATIONS) {
                        break
                    }
                }
                if (++count >= MAX_RECOMMENDATIONS) {
                    break
                }
            }
        } catch (e: IOException) {
            Log.e(TAG, "Unable to update recommendation", e)
        }
    }

    private fun buildPendingIntent(movie: Movie): PendingIntent {
        val detailsIntent = Intent(this, DetailsActivity::class.java)
        detailsIntent.putExtra("Movie", movie)

        val stackBuilder = TaskStackBuilder.create(this)
        stackBuilder.addParentStack(DetailsActivity::class.java)
        stackBuilder.addNextIntent(detailsIntent)

        // Ensure a unique PendingIntents, otherwise all
        // recommendations end up with the same PendingIntent
        detailsIntent.setAction(movie.getId().toString())

        val intent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
        return intent
    }

    companion object {
        private val TAG = "UpdateRecommendationsService"
        private val MAX_RECOMMENDATIONS = 3
    }
}

Java

public class UpdateRecommendationsService extends IntentService {
    private static final String TAG = "UpdateRecommendationsService";
    private static final int MAX_RECOMMENDATIONS = 3;

    public UpdateRecommendationsService() {
        super("RecommendationService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d(TAG, "Updating recommendation cards");
        HashMap<String, List<Movie>> recommendations = VideoProvider.getMovieList();
        if (recommendations == null) return;

        int count = 0;

        try {
            RecommendationBuilder builder = new RecommendationBuilder()
                    .setContext(getApplicationContext())
                    .setSmallIcon(R.drawable.videos_by_google_icon);

            for (Map.Entry<String, List<Movie>> entry : recommendations.entrySet()) {
                for (Movie movie : entry.getValue()) {
                    Log.d(TAG, "Recommendation - " + movie.getTitle());

                    builder.setBackground(movie.getCardImageUrl())
                            .setId(count + 1)
                            .setPriority(MAX_RECOMMENDATIONS - count)
                            .setTitle(movie.getTitle())
                            .setDescription(getString(R.string.popular_header))
                            .setImage(movie.getCardImageUrl())
                            .setIntent(buildPendingIntent(movie))
                            .build();

                    if (++count >= MAX_RECOMMENDATIONS) {
                        break;
                    }
                }
                if (++count >= MAX_RECOMMENDATIONS) {
                    break;
                }
            }
        } catch (IOException e) {
            Log.e(TAG, "Unable to update recommendation", e);
        }
    }

    private PendingIntent buildPendingIntent(Movie movie) {
        Intent detailsIntent = new Intent(this, DetailsActivity.class);
        detailsIntent.putExtra("Movie", movie);

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addParentStack(DetailsActivity.class);
        stackBuilder.addNextIntent(detailsIntent);
        // Ensure a unique PendingIntents, otherwise all
        // recommendations end up with the same PendingIntent
        detailsIntent.setAction(Long.toString(movie.getId()));

        PendingIntent intent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
        return intent;
    }
}

Pour que ce service soit reconnu par le système et exécuté, enregistrez-le à l'aide du fichier manifeste de votre application. L'extrait de code suivant montre comment déclarer cette classe en tant que service:

<manifest ... >
  <application ... >
    ...

    <service
            android:name="com.example.android.tvleanback.UpdateRecommendationsService"
            android:enabled="true" />
  </application>
</manifest>

Recommandations de compilation

Une fois que votre service de recommandations commence à s'exécuter, il doit créer des recommandations et les transmettre au framework Android. Le framework reçoit les recommandations en tant qu'objets Notification qui utilisent un modèle spécifique et sont marqués d'une catégorie spécifique.

Définir les valeurs

Pour définir les valeurs des éléments d'interface utilisateur pour la fiche de recommandation, vous devez créer une classe de compilateur qui suit le modèle de compilateur décrit comme suit. Tout d'abord, définissez les valeurs des éléments de la fiche de recommandation.

Kotlin

class RecommendationBuilder {
    ...

    fun setTitle(title: String): RecommendationBuilder {
        this.title = title
        return this
    }

    fun setDescription(description: String): RecommendationBuilder {
        this.description = description
        return this
    }

    fun setImage(uri: String): RecommendationBuilder {
        imageUri = uri
        return this
    }

    fun setBackground(uri: String): RecommendationBuilder {
        backgroundUri = uri
        return this
    }

...

Java

public class RecommendationBuilder {
    ...

    public RecommendationBuilder setTitle(String title) {
            this.title = title;
            return this;
        }

        public RecommendationBuilder setDescription(String description) {
            this.description = description;
            return this;
        }

        public RecommendationBuilder setImage(String uri) {
            imageUri = uri;
            return this;
        }

        public RecommendationBuilder setBackground(String uri) {
            backgroundUri = uri;
            return this;
        }
...

Créer la notification

Une fois les valeurs définies, créez la notification en attribuant les valeurs de la classe de compilateur à la notification, puis appelez NotificationCompat.Builder.build().

Veillez également à appeler setLocalOnly() pour que la notification NotificationCompat.BigPictureStyle ne s'affiche pas sur d'autres appareils.

L'exemple de code suivant montre comment créer une recommandation.

Kotlin

class RecommendationBuilder {
    ...

    @Throws(IOException::class)
    fun build(): Notification {
        ...

        val notification = NotificationCompat.BigPictureStyle(
        NotificationCompat.Builder(context)
                .setContentTitle(title)
                .setContentText(description)
                .setPriority(priority)
                .setLocalOnly(true)
                .setOngoing(true)
                .setColor(context.resources.getColor(R.color.fastlane_background))
                .setCategory(Notification.CATEGORY_RECOMMENDATION)
                .setLargeIcon(image)
                .setSmallIcon(smallIcon)
                .setContentIntent(intent)
                .setExtras(extras))
                .build()

        return notification
    }
}

Java

public class RecommendationBuilder {
    ...

    public Notification build() throws IOException {
        ...

        Notification notification = new NotificationCompat.BigPictureStyle(
                new NotificationCompat.Builder(context)
                        .setContentTitle(title)
                        .setContentText(description)
                        .setPriority(priority)
                        .setLocalOnly(true)
                        .setOngoing(true)
                        .setColor(context.getResources().getColor(R.color.fastlane_background))
                        .setCategory(Notification.CATEGORY_RECOMMENDATION)
                        .setLargeIcon(image)
                        .setSmallIcon(smallIcon)
                        .setContentIntent(intent)
                        .setExtras(extras))
                .build();

        return notification;
    }
}

Exécuter le service de recommandations

Le service de recommandations de votre application doit s'exécuter régulièrement pour créer des recommandations actuelles. Pour exécuter votre service, créez une classe qui exécute un minuteur et l'appelle à intervalles réguliers. L'exemple de code suivant étend la classe BroadcastReceiver pour démarrer l'exécution périodique d'un service de recommandations toutes les demi-heures:

Kotlin

class BootupActivity : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d(TAG, "BootupActivity initiated")
        if (intent.action.endsWith(Intent.ACTION_BOOT_COMPLETED)) {
            scheduleRecommendationUpdate(context)
        }
    }

    private fun scheduleRecommendationUpdate(context: Context) {
        Log.d(TAG, "Scheduling recommendations update")
        val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val recommendationIntent = Intent(context, UpdateRecommendationsService::class.java)
        val alarmIntent = PendingIntent.getService(context, 0, recommendationIntent, 0)
        alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                INITIAL_DELAY,
                AlarmManager.INTERVAL_HALF_HOUR,
                alarmIntent
        )
    }

    companion object {
        private val TAG = "BootupActivity"
        private val INITIAL_DELAY:Long = 5000
    }
}

Java

public class BootupActivity extends BroadcastReceiver {
    private static final String TAG = "BootupActivity";

    private static final long INITIAL_DELAY = 5000;

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "BootupActivity initiated");
        if (intent.getAction().endsWith(Intent.ACTION_BOOT_COMPLETED)) {
            scheduleRecommendationUpdate(context);
        }
    }

    private void scheduleRecommendationUpdate(Context context) {
        Log.d(TAG, "Scheduling recommendations update");

        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_HOUR,
                alarmIntent);
    }
}

Cette implémentation de la classe BroadcastReceiver doit s'exécuter après le démarrage de l'appareil TV sur lequel elle est installée. Pour ce faire, enregistrez cette classe dans le fichier manifeste de votre application avec un filtre d'intent qui écoute l'achèvement du processus de démarrage de l'appareil. L'exemple de code suivant montre comment ajouter cette configuration au fichier manifeste:

<manifest ... >
  <application ... >
    <receiver android:name="com.example.android.tvleanback.BootupActivity"
              android:enabled="true"
              android:exported="false">
      <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
      </intent-filter>
    </receiver>
  </application>
</manifest>

Important:Pour recevoir une notification de démarrage terminé, votre application doit demander l'autorisation RECEIVE_BOOT_COMPLETED. Pour en savoir plus, consultez ACTION_BOOT_COMPLETED.

Dans la méthode onHandleIntent() de votre classe de service de recommandations, publiez la recommandation sur le gestionnaire comme suit:

Kotlin

val notification = notificationBuilder.build()
notificationManager.notify(id, notification)

Java

Notification notification = notificationBuilder.build();
notificationManager.notify(id, notification);