Consigli su Android N e versioni precedenti

Quando interagiscono con la TV, gli utenti in genere preferiscono fornire un input minimo prima di guardare i contenuti. Uno scenario ideale per molti utenti della TV è: siediti, accendi e guarda. Il minimo passaggio per indirizzare gli utenti verso i contenuti di loro gradimento è in genere il percorso che preferiscono.

Nota: utilizza le API descritte qui per dare consigli solo nelle app eseguite con versioni di Android fino ad Android 7.1 (livello API 25) incluso. Per fornire suggerimenti per le app eseguite in Android 8.0 (livello API 26) e versioni successive, la tua app deve utilizzare i canali di suggerimenti.

Il framework Android favorisce l'interazione con l'input minimo fornendo una riga di suggerimenti nella schermata Home. I consigli sui contenuti vengono visualizzati nella prima riga della schermata Home della TV dopo il primo utilizzo del dispositivo. I suggerimenti forniti dal catalogo di contenuti della tua app possono aiutarti a far tornare gli utenti sulla tua app.

Figura 1. Un esempio della riga dei consigli.

Questa guida ti insegna come creare suggerimenti e integrarli al framework Android in modo che gli utenti possano trovare e godersi facilmente i contenuti della tua app. Consulta anche l'implementazione di esempio nell' app di esempio Leanback.

Best practice per i consigli

I consigli aiutano gli utenti a trovare rapidamente i contenuti e le app di loro gradimento. La creazione di suggerimenti che siano di alta qualità e pertinenti per gli utenti è un fattore importante per garantire un'ottima esperienza utente con l'app TV. Per questo motivo, devi considerare attentamente quali consigli presentare all'utente e gestirli da vicino.

Tipi di consigli

Quando crei suggerimenti, devi rimandare gli utenti ad attività di visualizzazione incomplete o suggerire attività che si estendono ai contenuti correlati. Ecco alcuni tipi specifici di consigli da prendere in considerazione:

  • Contenuti continui a fornire consigli per la puntata successiva affinché gli utenti possano riprendere a guardare una serie. In alternativa, utilizza i consigli di continuazione per film, programmi TV o podcast in pausa in modo che gli utenti possano riprendere a guardare i contenuti in pausa con pochi clic.
  • I consigli relativi a nuovi contenuti, ad esempio per una nuova puntata in prima visione, se l'utente ha finito di guardare un'altra serie. Inoltre, se l'app consente agli utenti di iscriversi, seguire o monitorare i contenuti, utilizza nuovi consigli per i contenuti non guardati nel loro elenco di contenuti monitorati.
  • Suggerimenti sui contenuti correlati basati sulla cronologia di visualizzazione degli utenti.

Per ulteriori informazioni su come progettare le schede dei consigli per un'esperienza utente ottimale, consulta la sezione Riga dei consigli nelle specifiche di progettazione di Android TV.

Aggiorna i consigli

Quando aggiorni i consigli, non limitarti a rimuoverli e ripubblicarli, perché così facendo i consigli verranno visualizzati alla fine della relativa riga. Una volta riprodotto un elemento di contenuto, ad esempio un film, rimuovilo dai consigli.

Personalizza i consigli

Puoi personalizzare le schede dei consigli in modo da trasmettere informazioni di branding, impostando elementi dell'interfaccia utente come l'immagine in primo piano e di sfondo della scheda, il colore, l'icona dell'app, il titolo e il sottotitolo. Per scoprire di più, consulta la sezione Riga dei consigli nelle specifiche di design di Android TV.

Consigli sul gruppo

Facoltativamente, puoi raggruppare i suggerimenti in base alla loro origine. Ad esempio, l'app potrebbe fornire due gruppi di consigli: consigli sui contenuti a cui l'utente è iscritto e consigli per nuovi contenuti di tendenza di cui l'utente potrebbe non essere a conoscenza.

Il sistema classifica e ordina i suggerimenti per ogni gruppo separatamente durante la creazione o l'aggiornamento della riga dei suggerimenti. Se fornisci informazioni sul gruppo per i tuoi suggerimenti, puoi assicurarti che questi non vengano ordinati sotto quelli non correlati.

Utilizza NotificationCompat.Builder.setGroup() per impostare la stringa della chiave di gruppo di un suggerimento. Ad esempio, per contrassegnare un consiglio come appartenente a un gruppo che include nuovi contenuti di tendenza, potresti chiamare setGroup("trending").

Crea un servizio di suggerimenti

I suggerimenti di contenuti vengono creati con l'elaborazione in background. Affinché la tua applicazione contribuisca ai suggerimenti, crea un servizio che aggiunga periodicamente schede dal catalogo della tua app all'elenco dei suggerimenti del sistema.

L'esempio di codice seguente illustra come estendere IntentService per creare un servizio di suggerimenti per la tua applicazione:

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;
    }
}

Affinché questo servizio venga riconosciuto dal sistema ed eseguito, registralo utilizzando il file manifest dell'app. Lo snippet di codice riportato di seguito illustra come dichiarare questa classe come servizio:

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

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

Suggerimenti per la creazione

Una volta avviato l'esecuzione, il servizio per suggerimenti deve creare suggerimenti e trasmetterli al framework Android. Il framework riceve i suggerimenti come oggetti Notification che utilizzano un modello specifico e sono contrassegnati con una categoria specifica.

Impostare i valori

Per impostare i valori degli elementi UI per la scheda dei suggerimenti, devi creare una classe del builder che segua il pattern del builder descritto come segue. Per prima cosa, imposta i valori degli elementi della scheda dei consigli.

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;
        }
...

Crea la notifica

Dopo aver impostato i valori, crei la notifica, assegnando i valori dalla classe del builder alla notifica e chiamando NotificationCompat.Builder.build().

Inoltre, assicurati di chiamare setLocalOnly() in modo che la notifica NotificationCompat.BigPictureStyle non venga visualizzata su altri dispositivi.

Il seguente esempio di codice mostra come creare un suggerimento.

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;
    }
}

Esegui il servizio di suggerimenti

Il servizio di suggerimenti dell'app deve essere eseguito periodicamente per creare suggerimenti attuali. Per eseguire il servizio, crea una classe che esegua un timer e lo richiami a intervalli regolari. Il seguente esempio di codice estende la classe BroadcastReceiver per avviare l'esecuzione periodica di un servizio di suggerimenti ogni mezz'ora:

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);
    }
}

Questa implementazione della classe BroadcastReceiver deve essere eseguita dopo l'avvio del dispositivo TV su cui è installato. A questo scopo, registra questa classe nel manifest dell'app con un filtro per intent che ascolti il completamento del processo di avvio del dispositivo. Il seguente codice di esempio mostra come aggiungere questa configurazione al file manifest:

<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>

Importante: per ricevere una notifica di avvio completato, è necessario che la tua app richieda l'autorizzazione RECEIVE_BOOT_COMPLETED. Per ulteriori informazioni, vedi ACTION_BOOT_COMPLETED.

Nel metodo onHandleIntent() della classe di servizio per suggerimenti, pubblica il suggerimento per l'amministratore come segue:

Kotlin

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

Java

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