Android TV utilizza l'interfaccia di ricerca di Android per recuperare i dati dei contenuti dalle app installate e fornire i risultati di ricerca all'utente. I dati dei contenuti della tua app possono essere inclusi in questi risultati per consentire all'utente di accedere immediatamente ai contenuti della tua app.
La tua app deve fornire ad Android TV i campi di dati da cui Android TV può generare risultati di ricerca suggeriti man mano che l'utente inserisce i caratteri nella finestra di dialogo di ricerca. A questo scopo, la tua app deve implementare un
content provider che fornisca
i suggerimenti insieme a un
searchable.xml file di configurazione che descriva il content
provider e altre informazioni vitali per Android TV. È necessaria anche un'attività che gestisca l'intent che viene attivato quando l'utente seleziona un risultato di ricerca suggerito. Per
maggiori dettagli, consulta Aggiungere
suggerimenti di ricerca personalizzati. Questa guida illustra i punti principali specifici delle app Android TV.
Prima di leggere questa guida, assicurati di conoscere i concetti spiegati nella guida all'API Search. Inoltre, consulta Aggiungere la funzionalità di ricerca.
Il codice campione in questa guida proviene dall' app di esempio Leanback .
Identificare le colonne
La classe SearchManager descrive i campi di dati che si aspetta rappresentandoli come colonne di un database locale. Indipendentemente dal formato dei dati, devi mappare i campi di dati a queste colonne, in genere nella classe che accede ai dati dei contenuti. Per informazioni sulla creazione
di una classe che mappa i dati esistenti ai campi obbligatori, consulta
Creare una tabella di suggerimenti.
La classe SearchManager include diverse colonne per Android TV. Alcune delle colonne più importanti sono descritte nella tabella seguente.
| Valore | Descrizione |
|---|---|
SUGGEST_COLUMN_TEXT_1 |
Il nome dei contenuti (obbligatorio) |
SUGGEST_COLUMN_TEXT_2 |
Una descrizione testuale dei contenuti |
SUGGEST_COLUMN_RESULT_CARD_IMAGE |
Un'immagine, un poster o una copertina per i contenuti |
SUGGEST_COLUMN_CONTENT_TYPE |
Il tipo MIME dei contenuti multimediali |
SUGGEST_COLUMN_VIDEO_WIDTH |
La larghezza della risoluzione dei contenuti multimediali |
SUGGEST_COLUMN_VIDEO_HEIGHT |
L'altezza della risoluzione dei contenuti multimediali |
SUGGEST_COLUMN_PRODUCTION_YEAR |
L'anno di produzione dei contenuti (obbligatorio) |
SUGGEST_COLUMN_DURATION |
La durata in millisecondi dei contenuti multimediali (obbligatorio) |
Il framework di ricerca richiede le seguenti colonne:
Quando i valori di queste colonne per i tuoi contenuti corrispondono ai valori degli stessi contenuti di altri provider trovati dai server di Google, il sistema fornisce un link diretto alla tua app nella visualizzazione dei dettagli dei contenuti, insieme ai link alle app di altri provider. Questo argomento è trattato più nel dettaglio nella sezione Link diretto alla tua app nella schermata dei dettagli.
La classe di database dell'applicazione potrebbe definire le colonne come segue:
Kotlin
class VideoDatabase { companion object { // The columns we'll include in the video database table val KEY_NAME = SearchManager.SUGGEST_COLUMN_TEXT_1 val KEY_DESCRIPTION = SearchManager.SUGGEST_COLUMN_TEXT_2 val KEY_ICON = SearchManager.SUGGEST_COLUMN_RESULT_CARD_IMAGE val KEY_DATA_TYPE = SearchManager.SUGGEST_COLUMN_CONTENT_TYPE val KEY_IS_LIVE = SearchManager.SUGGEST_COLUMN_IS_LIVE val KEY_VIDEO_WIDTH = SearchManager.SUGGEST_COLUMN_VIDEO_WIDTH val KEY_VIDEO_HEIGHT = SearchManager.SUGGEST_COLUMN_VIDEO_HEIGHT val KEY_AUDIO_CHANNEL_CONFIG = SearchManager.SUGGEST_COLUMN_AUDIO_CHANNEL_CONFIG val KEY_PURCHASE_PRICE = SearchManager.SUGGEST_COLUMN_PURCHASE_PRICE val KEY_RENTAL_PRICE = SearchManager.SUGGEST_COLUMN_RENTAL_PRICE val KEY_RATING_STYLE = SearchManager.SUGGEST_COLUMN_RATING_STYLE val KEY_RATING_SCORE = SearchManager.SUGGEST_COLUMN_RATING_SCORE val KEY_PRODUCTION_YEAR = SearchManager.SUGGEST_COLUMN_PRODUCTION_YEAR val KEY_COLUMN_DURATION = SearchManager.SUGGEST_COLUMN_DURATION val KEY_ACTION = SearchManager.SUGGEST_COLUMN_INTENT_ACTION ... } ... }
Java
public class VideoDatabase { // The columns we'll include in the video database table public static final String KEY_NAME = SearchManager.SUGGEST_COLUMN_TEXT_1; public static final String KEY_DESCRIPTION = SearchManager.SUGGEST_COLUMN_TEXT_2; public static final String KEY_ICON = SearchManager.SUGGEST_COLUMN_RESULT_CARD_IMAGE; public static final String KEY_DATA_TYPE = SearchManager.SUGGEST_COLUMN_CONTENT_TYPE; public static final String KEY_IS_LIVE = SearchManager.SUGGEST_COLUMN_IS_LIVE; public static final String KEY_VIDEO_WIDTH = SearchManager.SUGGEST_COLUMN_VIDEO_WIDTH; public static final String KEY_VIDEO_HEIGHT = SearchManager.SUGGEST_COLUMN_VIDEO_HEIGHT; public static final String KEY_AUDIO_CHANNEL_CONFIG = SearchManager.SUGGEST_COLUMN_AUDIO_CHANNEL_CONFIG; public static final String KEY_PURCHASE_PRICE = SearchManager.SUGGEST_COLUMN_PURCHASE_PRICE; public static final String KEY_RENTAL_PRICE = SearchManager.SUGGEST_COLUMN_RENTAL_PRICE; public static final String KEY_RATING_STYLE = SearchManager.SUGGEST_COLUMN_RATING_STYLE; public static final String KEY_RATING_SCORE = SearchManager.SUGGEST_COLUMN_RATING_SCORE; public static final String KEY_PRODUCTION_YEAR = SearchManager.SUGGEST_COLUMN_PRODUCTION_YEAR; public static final String KEY_COLUMN_DURATION = SearchManager.SUGGEST_COLUMN_DURATION; public static final String KEY_ACTION = SearchManager.SUGGEST_COLUMN_INTENT_ACTION; ...
Quando crei la mappatura dalle colonne SearchManager ai campi di dati, devi anche specificare _ID per assegnare a ogni riga un ID univoco.
Kotlin
companion object { .... private fun buildColumnMap(): Map<String, String> { return mapOf( KEY_NAME to KEY_NAME, KEY_DESCRIPTION to KEY_DESCRIPTION, KEY_ICON to KEY_ICON, KEY_DATA_TYPE to KEY_DATA_TYPE, KEY_IS_LIVE to KEY_IS_LIVE, KEY_VIDEO_WIDTH to KEY_VIDEO_WIDTH, KEY_VIDEO_HEIGHT to KEY_VIDEO_HEIGHT, KEY_AUDIO_CHANNEL_CONFIG to KEY_AUDIO_CHANNEL_CONFIG, KEY_PURCHASE_PRICE to KEY_PURCHASE_PRICE, KEY_RENTAL_PRICE to KEY_RENTAL_PRICE, KEY_RATING_STYLE to KEY_RATING_STYLE, KEY_RATING_SCORE to KEY_RATING_SCORE, KEY_PRODUCTION_YEAR to KEY_PRODUCTION_YEAR, KEY_COLUMN_DURATION to KEY_COLUMN_DURATION, KEY_ACTION to KEY_ACTION, BaseColumns._ID to ("rowid AS " + BaseColumns._ID), SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID to ("rowid AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID), SearchManager.SUGGEST_COLUMN_SHORTCUT_ID to ("rowid AS " + SearchManager.SUGGEST_COLUMN_SHORTCUT_ID) ) } }
Java
... private static HashMap<String, String> buildColumnMap() { HashMap<String, String> map = new HashMap<String, String>(); map.put(KEY_NAME, KEY_NAME); map.put(KEY_DESCRIPTION, KEY_DESCRIPTION); map.put(KEY_ICON, KEY_ICON); map.put(KEY_DATA_TYPE, KEY_DATA_TYPE); map.put(KEY_IS_LIVE, KEY_IS_LIVE); map.put(KEY_VIDEO_WIDTH, KEY_VIDEO_WIDTH); map.put(KEY_VIDEO_HEIGHT, KEY_VIDEO_HEIGHT); map.put(KEY_AUDIO_CHANNEL_CONFIG, KEY_AUDIO_CHANNEL_CONFIG); map.put(KEY_PURCHASE_PRICE, KEY_PURCHASE_PRICE); map.put(KEY_RENTAL_PRICE, KEY_RENTAL_PRICE); map.put(KEY_RATING_STYLE, KEY_RATING_STYLE); map.put(KEY_RATING_SCORE, KEY_RATING_SCORE); map.put(KEY_PRODUCTION_YEAR, KEY_PRODUCTION_YEAR); map.put(KEY_COLUMN_DURATION, KEY_COLUMN_DURATION); map.put(KEY_ACTION, KEY_ACTION); map.put(BaseColumns._ID, "rowid AS " + BaseColumns._ID); map.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, "rowid AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID); map.put(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID, "rowid AS " + SearchManager.SUGGEST_COLUMN_SHORTCUT_ID); return map; } ...
Nell'esempio precedente, nota la mappatura al campo SUGGEST_COLUMN_INTENT_DATA_ID. Questa è la parte dell'URI che rimanda ai contenuti univoci dei dati in questa riga, ovvero l'ultima parte dell'URI, che descrive dove sono archiviati i contenuti. La prima parte dell'URI,
quando è comune a tutte le righe della tabella, viene impostata nel
searchable.xml file come attributo
android:searchSuggestIntentData, come descritto nella sezione
Gestire i suggerimenti di ricerca.
Se la prima parte dell'URI è diversa per ogni riga della tabella, mappa il valore con il campo SUGGEST_COLUMN_INTENT_DATA.
Quando l'utente seleziona questi contenuti, l'intent che viene attivato fornisce i dati dell'intent dalla
combinazione di SUGGEST_COLUMN_INTENT_DATA_ID
e dell'attributo android:searchSuggestIntentData o del valore del campo
SUGGEST_COLUMN_INTENT_DATA.
Fornire dati dei suggerimenti di ricerca
Implementa un content provider
per restituire i suggerimenti dei termini di ricerca alla finestra di dialogo di ricerca di Android TV. Il sistema esegue una query sul content provider per i suggerimenti chiamando il metodo query() ogni volta che viene digitata una lettera. Nell'implementazione di query(), il content provider cerca i dati dei suggerimenti e restituisce un Cursor che rimanda alle righe che hai designato per i suggerimenti.
Kotlin
fun query(uri: Uri, projection: Array<String>, selection: String, selectionArgs: Array<String>, sortOrder: String): Cursor { // Use the UriMatcher to see what kind of query we have and format the db query accordingly when (URI_MATCHER.match(uri)) { SEARCH_SUGGEST -> { Log.d(TAG, "search suggest: ${selectionArgs[0]} URI: $uri") if (selectionArgs == null) { throw IllegalArgumentException( "selectionArgs must be provided for the Uri: $uri") } return getSuggestions(selectionArgs[0]) } else -> throw IllegalArgumentException("Unknown Uri: $uri") } } private fun getSuggestions(query: String): Cursor { val columns = arrayOf<String>( BaseColumns._ID, VideoDatabase.KEY_NAME, VideoDatabase.KEY_DESCRIPTION, VideoDatabase.KEY_ICON, VideoDatabase.KEY_DATA_TYPE, VideoDatabase.KEY_IS_LIVE, VideoDatabase.KEY_VIDEO_WIDTH, VideoDatabase.KEY_VIDEO_HEIGHT, VideoDatabase.KEY_AUDIO_CHANNEL_CONFIG, VideoDatabase.KEY_PURCHASE_PRICE, VideoDatabase.KEY_RENTAL_PRICE, VideoDatabase.KEY_RATING_STYLE, VideoDatabase.KEY_RATING_SCORE, VideoDatabase.KEY_PRODUCTION_YEAR, VideoDatabase.KEY_COLUMN_DURATION, VideoDatabase.KEY_ACTION, SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID ) return videoDatabase.getWordMatch(query.toLowerCase(), columns) }
Java
@Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // Use the UriMatcher to see what kind of query we have and format the db query accordingly switch (URI_MATCHER.match(uri)) { case SEARCH_SUGGEST: Log.d(TAG, "search suggest: " + selectionArgs[0] + " URI: " + uri); if (selectionArgs == null) { throw new IllegalArgumentException( "selectionArgs must be provided for the Uri: " + uri); } return getSuggestions(selectionArgs[0]); default: throw new IllegalArgumentException("Unknown Uri: " + uri); } } private Cursor getSuggestions(String query) { query = query.toLowerCase(); String[] columns = new String[]{ BaseColumns._ID, VideoDatabase.KEY_NAME, VideoDatabase.KEY_DESCRIPTION, VideoDatabase.KEY_ICON, VideoDatabase.KEY_DATA_TYPE, VideoDatabase.KEY_IS_LIVE, VideoDatabase.KEY_VIDEO_WIDTH, VideoDatabase.KEY_VIDEO_HEIGHT, VideoDatabase.KEY_AUDIO_CHANNEL_CONFIG, VideoDatabase.KEY_PURCHASE_PRICE, VideoDatabase.KEY_RENTAL_PRICE, VideoDatabase.KEY_RATING_STYLE, VideoDatabase.KEY_RATING_SCORE, VideoDatabase.KEY_PRODUCTION_YEAR, VideoDatabase.KEY_COLUMN_DURATION, VideoDatabase.KEY_ACTION, SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID }; return videoDatabase.getWordMatch(query, columns); } ...
Nel file manifest, il content provider riceve un trattamento speciale. Anziché essere
contrassegnato come attività, viene descritto come
<provider>. Il provider include l'attributo android:authorities per indicare al sistema lo spazio dei nomi del content provider. Inoltre, devi impostare l'attributo android:exported su "true" in modo che la ricerca globale di Android possa utilizzare i risultati restituiti.
<provider android:name="com.example.android.tvleanback.VideoContentProvider" android:authorities="com.example.android.tvleanback" android:exported="true" />
Gestire i suggerimenti di ricerca
La tua app deve includere un
res/xml/searchable.xml file per configurare le impostazioni dei suggerimenti di ricerca.
Nel file res/xml/searchable.xml, includi
l'attributo
android:searchSuggestAuthority per indicare al sistema lo spazio dei nomi del
content provider. Questo valore deve corrispondere al valore della stringa specificato nell'
android:authorities
attributo dell'elemento <provider>
nel file AndroidManifest.xml.
Includi anche un'etichetta, ovvero il nome dell'applicazione. Le impostazioni di ricerca del sistema utilizzano questa etichetta quando enumerano le app ricercabili.
Il file searchable.xmlfile
deve includere anche
android:searchSuggestIntentAction con il valore "android.intent.action.VIEW"
per definire l'azione dell'intent per fornire un suggerimento personalizzato. Questa azione è diversa dall'azione dell'intent
per fornire un termine di ricerca, come descritto nella sezione seguente.
Per altri modi per dichiarare l'azione dell'intent per i suggerimenti,
consulta Dichiarare l'
azione dell'intent.
Oltre all'azione dell'intent, la tua app deve fornire i dati dell'intent, che specifichi con l'
android:searchSuggestIntentData attributo. Questa è la prima parte dell'URI che rimanda ai contenuti, che descrive la parte dell'URI comune a tutte le righe della tabella di mappatura per questi contenuti. La parte dell'URI univoca per ogni riga viene stabilita con il campo SUGGEST_COLUMN_INTENT_DATA_ID,
come descritto nella sezione Identificare le colonne.
Per altri modi per dichiarare i dati dell'intent per i suggerimenti, consulta
Dichiarare
i dati dell'intent.
L'attributo android:searchSuggestSelection=" ?" specifica il valore passato come parametro selection del metodo query(). Il valore del punto interrogativo (?) viene sostituito dal testo della query.
Infine, devi includere anche l'attributo
android:includeInGlobalSearch con il valore "true". Ecco un esempio di file searchable.xml:
<searchable xmlns:android="http://schemas.android.com/apk/res/android" android:label="@string/search_label" android:hint="@string/search_hint" android:searchSettingsDescription="@string/settings_description" android:searchSuggestAuthority="com.example.android.tvleanback" android:searchSuggestIntentAction="android.intent.action.VIEW" android:searchSuggestIntentData="content://com.example.android.tvleanback/video_database_leanback" android:searchSuggestSelection=" ?" android:searchSuggestThreshold="1" android:includeInGlobalSearch="true"> </searchable>
Gestire i termini di ricerca
Non appena la finestra di dialogo di ricerca contiene una parola che corrisponde al valore di una delle colonne dell'app, come
descritto nella sezione Identificare le colonne, il sistema attiva l'intent
ACTION_SEARCH.
L'attività nella tua app che gestisce questo intent cerca nel repository le colonne con la parola specificata nei relativi valori e restituisce un elenco di elementi di contenuti con queste colonne. Nel file AndroidManifest.xml, designa l'attività che gestisce l'intent ACTION_SEARCH come mostrato nell'esempio seguente:
... <activity android:name="com.example.android.tvleanback.DetailsActivity" android:exported="true"> <!-- Receives the search request. --> <intent-filter> <action android:name="android.intent.action.SEARCH" /> <!-- No category needed, because the Intent will specify this class component --> </intent-filter> <!-- Points to searchable meta data. --> <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" /> </activity> ... <!-- Provides search suggestions for keywords against video meta data. --> <provider android:name="com.example.android.tvleanback.VideoContentProvider" android:authorities="com.example.android.tvleanback" android:exported="true" /> ...
L'attività deve anche descrivere la configurazione ricercabile con un riferimento al
searchable.xml file.
Per utilizzare la finestra di dialogo di ricerca globale,
il manifest deve descrivere l'attività che deve ricevere le query di ricerca. Il manifest deve anche
descrivere l'elemento <provider>
, esattamente come descritto nel file searchable.xml.
Link diretto alla tua app nella schermata dei dettagli
Se hai configurato la ricerca come descritto nella sezione Gestire i suggerimenti e hai mappato i campi SUGGEST_COLUMN_TEXT_1,SUGGEST_COLUMN_PRODUCTION_YEAR, eSUGGEST_COLUMN_DURATION come descritto nella sezione Identificare le colonne, nella schermata dei dettagli che viene avviata quando
l'utente seleziona un risultato di ricerca viene visualizzato un
link diretto a un'azione di visualizzazione per i tuoi contenuti:
Quando l'utente seleziona il link alla tua app, identificato dal pulsante **Disponibile su** nella
schermata dei dettagli, il sistema avvia l'attività che gestisce ACTION_VIEW
impostato come
android:searchSuggestIntentAction con il valore "android.intent.action.VIEW" in
il file searchable.xml.
Puoi anche configurare un intent personalizzato per avviare l'attività. Questo è illustrato nell'
app di esempio Leanback
. Tieni presente che l'app di esempio avvia il proprio LeanbackDetailsFragment per mostrare i dettagli dei contenuti multimediali selezionati; nelle tue app, avvia immediatamente l'attività che riproduce i contenuti multimediali per evitare all'utente di fare uno o due clic in più.
Comportamento di ricerca
La ricerca è disponibile su Android TV dalla schermata Home e dall'interno dell'app. I risultati di ricerca sono diversi per questi due casi.
Cercare dalla schermata Home
Quando l'utente esegue una ricerca dalla schermata Home, il primo risultato viene visualizzato in una scheda dell'entità. Se sono presenti app in grado di riprodurre i contenuti, nella parte inferiore della scheda viene visualizzato un link a ciascuna di esse:
Non puoi inserire un'app nella scheda dell'entità a livello di programmazione. Per essere inclusi come opzione di riproduzione, i risultati di ricerca di un'app devono corrispondere al titolo, all'anno e alla durata dei contenuti cercati.
Potrebbero essere disponibili altri risultati di ricerca sotto la scheda. Per visualizzarli, l'utente deve premere il telecomando e scorrere. I risultati per ogni app vengono visualizzati in una riga separata. Non puoi controllare l'ordine delle righe. Le app che supportano le azioni di visualizzazione sono elencate per prime.
Cercare dall'app
L'utente può anche avviare una ricerca dall'interno dell'app attivando il microfono dal telecomando o dal controller del gamepad. I risultati di ricerca vengono visualizzati in una singola riga sopra i contenuti dell'app. La tua app genera i risultati di ricerca utilizzando il proprio provider di ricerca globale.
Scopri di più
Per scoprire di più sulla ricerca in un'app TV, consulta Integrare le funzionalità di ricerca di Android nella tua app e Aggiungere la funzionalità di ricerca.
Per ulteriori informazioni su come personalizzare l'esperienza di ricerca in-app con un SearchFragment, consulta
Eseguire ricerche nelle app TV.