am aa7c1f68: am 13d31b0a: am d7d1411a: am e2b44f86: docs: Making TV Apps Searchable - new training
* commit 'aa7c1f6845dcac1ade80196280ead40958bd1acd':
docs: Making TV Apps Searchable - new training
diff --git a/docs/html/guide/topics/search/searchable-config.jd b/docs/html/guide/topics/search/searchable-config.jd
index fc13c04..9d2fa94 100644
--- a/docs/html/guide/topics/search/searchable-config.jd
+++ b/docs/html/guide/topics/search/searchable-config.jd
@@ -32,26 +32,26 @@
<pre class="stx">
<?xml version="1.0" encoding="utf-8"?>
<<a href="#searchable-element">searchable</a> xmlns:android="http://schemas.android.com/apk/res/android"
- android:label="<em>string resource</em>"
- android:hint="<em>string resource</em>"
- android:searchMode=["queryRewriteFromData" | "queryRewriteFromText"]
- android:searchButtonText="<em>string resource</em>"
- android:inputType="<em>{@link android.R.attr#inputType}</em>"
- android:imeOptions="<em>{@link android.R.attr#imeOptions}</em>"
- android:searchSuggestAuthority="<em>string</em>"
- android:searchSuggestPath="<em>string</em>"
- android:searchSuggestSelection="<em>string</em>"
- android:searchSuggestIntentAction="<em>string</em>"
- android:searchSuggestIntentData="<em>string</em>"
- android:searchSuggestThreshold="<em>int</em>"
- android:includeInGlobalSearch=["true" | "false"]
- android:searchSettingsDescription="<em>string resource</em>"
- android:queryAfterZeroResults=["true" | "false"]
- android:voiceSearchMode=["showVoiceSearchButton" | "launchWebSearch" | "launchRecognizer"]
- android:voiceLanguageModel=["free-form" | "web_search"]
- android:voicePromptText="<em>string resource</em>"
- android:voiceLanguage="<em>string</em>"
- android:voiceMaxResults="<em>int</em>"
+ android:<a href="#label">label</a>="<em>string resource</em>"
+ android:<a href="#hint">hint</a>="<em>string resource</em>"
+ android:<a href="#searchMode">searchMode</a>=["queryRewriteFromData" | "queryRewriteFromText"]
+ android:<a href="#searchButtonText">searchButtonText</a>="<em>string resource</em>"
+ android:<a href="#inputType">inputType</a>="<em>{@link android.R.attr#inputType}</em>"
+ android:<a href="#imeOptions">imeOptions</a>="<em>{@link android.R.attr#imeOptions}</em>"
+ android:<a href="#searchSuggestAuthority">searchSuggestAuthority</a>="<em>string</em>"
+ android:<a href="#searchSuggestPath">searchSuggestPath</a>="<em>string</em>"
+ android:<a href="#searchSuggestSelection">searchSuggestSelection</a>="<em>string</em>"
+ android:<a href="#searchSuggestIntentAction">searchSuggestIntentAction</a>="<em>string</em>"
+ android:<a href="#searchSuggestIntentData">searchSuggestIntentData</a>="<em>string</em>"
+ android:<a href="#searchSuggestThreshold">searchSuggestThreshold</a>="<em>int</em>"
+ android:<a href="#includeInGlobalSearch">includeInGlobalSearch</a>=["true" | "false"]
+ android:<a href="#searchSettingsDescription">searchSettingsDescription</a>="<em>string resource</em>"
+ android:<a href="#queryAfterZeroResults">queryAfterZeroResults</a>=["true" | "false"]
+ android:<a href="#voiceSearchMode">voiceSearchMode</a>=["showVoiceSearchButton" | "launchWebSearch" | "launchRecognizer"]
+ android:<a href="#voiceLanguageModel">voiceLanguageModel</a>=["free-form" | "web_search"]
+ android:<a href="#voicePromptText">voicePromptText</a>="<em>string resource</em>"
+ android:<a href="#voiceLanguage">voiceLanguage</a>="<em>string</em>"
+ android:<a href="#voiceMaxResults">voiceMaxResults</a>="<em>int</em>"
>
<<a href="#actionkey-element">actionkey</a>
android:keycode="<em>{@link android.view.KeyEvent KEYCODE}</em>"
@@ -69,7 +69,7 @@
<dd>Defines all search configurations used by the Android system to provide assisted search.
<p class="caps">attributes:</p>
<dl class="atn-list">
- <dt><code>android:label</code></dt>
+ <dt><a name="label"></a><code>android:label</code></dt>
<dd><em>String resource</em>. (Required.) The name of your application.
It should be the same as the name applied to the {@code android:label} attribute of your <a
href="{@docRoot}guide/topics/manifest/activity-element.html#label">{@code <activity>}</a> or
@@ -78,14 +78,14 @@
<code>android:includeInGlobalSearch</code> to "true", in which case, this label is used to identify
your application as a searchable item in the system's search settings.</dd>
- <dt><code>android:hint</code></dt>
+ <dt><a name="hint"></a><code>android:hint</code></dt>
<dd><em>String resource</em>. (Recommended.) The text to display in the search text field when
no text has been entered. It provides a hint to the user about what
content is searchable. For consistency with other Android applications, you should format the
string for {@code android:hint} as "Search <em><content-or-product></em>". For example,
"Search songs and artists" or "Search YouTube".</dd>
- <dt><code>android:searchMode</code></dt>
+ <dt><a name="searchMode"></a><code>android:searchMode</code></dt>
<dd><em>Keyword</em>. Sets additional modes that control the search presentation.
Currently available modes define how the query text should be rewritten when a custom suggestion
receives focus. The following mode values are accepted:
@@ -109,19 +109,19 @@
href="adding-custom-suggestions.html#RewritingQueryText">Adding Custom Suggestions</a>.</p>
</dd>
- <dt><code>android:searchButtonText</code></dt>
+ <dt><a name="searchButtonText"></a><code>android:searchButtonText</code></dt>
<dd><em>String resource</em>. The text to display in the button that executes search. By
default, the button shows a search icon (a magnifying glass), which is ideal for
internationalization, so you should not use this attribute to change the button unless the
behavior is something other than a search (such as a URL request in a web browser).</dd>
- <dt><code>android:inputType</code></dt>
+ <dt><a name="inputType"></a><code>android:inputType</code></dt>
<dd><em>Keyword</em>. Defines the type of input method (such as the type of soft keyboard)
-to use. For most searches, in which free-form text is expected, you don't
+to use. For most searches, in which free-form text is expected, you don't
need this attribute. See {@link android.R.attr#inputType} for a list of suitable values for this
attribute.</dd>
- <dt><code>android:imeOptions</code></dt>
+ <dt><a name="imeOptions"></a><code>android:imeOptions</code></dt>
<dd><em>Keyword</em>. Supplies additional options for the input method.
For most searches, in which free-form text is expected, you don't need this attribute. The
default IME is "actionSearch" (provides the "search" button instead of a carriage
@@ -139,12 +139,12 @@
{@code <searchable>} attributes:</p><br/>
<dl class="atn-list">
- <dt><code>android:searchSuggestAuthority</code></dt>
+ <dt><a name="searchSuggestAuthority"></a><code>android:searchSuggestAuthority</code></dt>
<dd><em>String</em>. (Required to provide search suggestions.)
This value must match the authority string provided in the {@code android:authorities}
attribute of the Android manifest {@code <provider>} element.</dd>
- <dt><code>android:searchSuggestPath</code></dt>
+ <dt><a name="searchSuggestPath"></a><code>android:searchSuggestPath</code></dt>
<dd><em>String</em>. This path is used as a portion of the suggestions
query {@link android.net.Uri}, after the prefix and authority, but before
the standard suggestions path.
@@ -152,7 +152,7 @@
of suggestions (such as for different data types) and you need
a way to disambiguate the suggestions queries when you receive them.</dd>
- <dt><code>android:searchSuggestSelection</code></dt>
+ <dt><a name="searchSuggestSelection"></a><code>android:searchSuggestSelection</code></dt>
<dd><em>String</em>. This value is passed into your
query function as the {@code selection} parameter. Typically this is a WHERE clause
for your database, and should contain a single question mark, which is a placeholder for the
@@ -160,22 +160,22 @@
can also use any non-null value to trigger the delivery of the query text via the {@code
selectionArgs} parameter (and then ignore the {@code selection} parameter).</dd>
- <dt><code>android:searchSuggestIntentAction</code></dt>
+ <dt><a name="searchSuggestIntentAction"></a><code>android:searchSuggestIntentAction</code></dt>
<dd><em>String</em>. The default intent action to be used when a user
clicks on a custom search suggestion (such as {@code "android.intent.action.VIEW"}).
If this is not overridden by the selected suggestion (via the {@link
android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column), this value is placed in the action
field of the {@link android.content.Intent} when the user clicks a suggestion.</dd>
- <dt><code>android:searchSuggestIntentData</code></dt>
+ <dt><a name="searchSuggestIntentData"></a><code>android:searchSuggestIntentData</code></dt>
<dd><em>String</em>. The default intent data to be used when a user
clicks on a custom search suggestion.
If not overridden by the selected suggestion (via the {@link
android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column), this value is
- placed in the data field of the {@link android.content.Intent} when the user clicks
+ placed in the data field of the {@link android.content.Intent} when the user clicks
a suggestion.</dd>
- <dt><code>android:searchSuggestThreshold</code></dt>
+ <dt><a name="searchSuggestThreshold"></a><code>android:searchSuggestThreshold</code></dt>
<dd><em>Integer</em>. The minimum number of characters needed to
trigger a suggestion look-up. Only guarantees that the system will not query your
content provider for anything shorter than the threshold. The default value is 0.</dd>
@@ -192,20 +192,20 @@
following {@code <searchable>} attributes:</p><br/>
<dl class="atn-list">
- <dt><code>android:includeInGlobalSearch</code></dt>
+ <dt><a name="includeInGlobalSearch"></a><code>android:includeInGlobalSearch</code></dt>
<dd><em>Boolean</em>. (Required to provide search suggestions in
Quick Search Box.) Set to "true" if you want your suggestions to be
included in the globally accessible Quick Search Box. The user must
still enable your application as a searchable item in the system search settings before
your suggestions will appear in Quick Search Box.</dd>
- <dt><code>android:searchSettingsDescription</code></dt>
+ <dt><a name="searchSettingsDescription"></a><code>android:searchSettingsDescription</code></dt>
<dd><em>String</em>. Provides a brief description of the search suggestions that you provide
to Quick Search Box, which is displayed in the searchable items entry for your application.
Your description should concisely describe the content that is searchable. For example, "Artists,
albums, and tracks" for a music application, or "Saved notes" for a notepad application.</dd>
- <dt><code>android:queryAfterZeroResults</code></dt>
+ <dt><a name="queryAfterZeroResults"></a><code>android:queryAfterZeroResults</code></dt>
<dd><em>Boolean</em>. Set to "true" if you want your content provider to be invoked for
supersets of queries that have returned zero results in the past. For example, if
your content provider returned zero results for "bo", it should be requiried for "bob". If set to
@@ -222,7 +222,7 @@
following {@code <searchable>} attributes:</p><br/>
<dl class="atn-list">
- <dt><code>android:voiceSearchMode</code></dt>
+ <dt><a name="voiceSearchMode"></a><code>android:voiceSearchMode</code></dt>
<dd><em>Keyword</em>. (Required to provide voice search capabilities.)
Enables voice search, with a specific mode for voice search.
(Voice search may not be provided by the device, in which case these flags
@@ -252,7 +252,7 @@
</table>
</dd>
- <dt><code>android:voiceLanguageModel</code></dt>
+ <dt><a name="voiceLanguageModel"></a><code>android:voiceLanguageModel</code></dt>
<dd><em>Keyword</em>. The language model that
should be used by the voice recognition system. The following values are accepted:
<table>
@@ -268,20 +268,20 @@
available in more languages than "free_form".</td>
</tr>
</table>
- <p>Also see
+ <p>Also see
{@link android.speech.RecognizerIntent#EXTRA_LANGUAGE_MODEL} for more
information.</p></dd>
- <dt><code>android:voicePromptText</code></dt>
+ <dt><a name="voicePromptText"></a><code>android:voicePromptText</code></dt>
<dd><em>String</em>. An additional message to display in the voice input dialog.</dd>
- <dt><code>android:voiceLanguage</code></dt>
+ <dt><a name="voiceLanguage"></a><code>android:voiceLanguage</code></dt>
<dd><em>String</em>. The spoken language to be expected, expressed as the string value of
a constants in {@link java.util.Locale} (such as {@code "de"} for German or {@code "fr"} for
French). This is needed only if it is different from the current value of {@link
java.util.Locale#getDefault() Locale.getDefault()}.</dd>
- <dt><code>android:voiceMaxResults</code></dt>
+ <dt><a name="voiceMaxResults"></a><code>android:voiceMaxResults</code></dt>
<dd><em>Integer</em>. Forces the maximum number of results to return,
including the "best" result which is always provided as the {@link
android.content.Intent#ACTION_SEARCH} intent's primary
@@ -308,7 +308,7 @@
other three attributes in order to define the search action.</p>
<p class="caps">attributes:</p>
<dl class="atn-list">
- <dt><code>android:keycode</code></dt>
+ <dt><a name="keycode"></a><code>android:keycode</code></dt>
<dd><em>String</em>. (Required.) A key code from {@link
android.view.KeyEvent} that represents the action key
you wish to respond to (for example {@code "KEYCODE_CALL"}). This is added to the
@@ -318,7 +318,7 @@
keys are supported for a search action, as many of them are used for typing, navigation, or system
functions.</dd>
- <dt><code>android:queryActionMsg</code></dt>
+ <dt><a name="queryActionMsg"></a><code>android:queryActionMsg</code></dt>
<dd><em>String</em>. An action message to be sent if the action key is pressed while the
user is entering query text. This is added to the
{@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that the system
@@ -326,17 +326,17 @@
{@link android.content.Intent#getStringExtra
getStringExtra(SearchManager.ACTION_MSG)}.</dd>
- <dt><code>android:suggestActionMsg</code></dt>
+ <dt><a name="suggestActionMsg"></a><code>android:suggestActionMsg</code></dt>
<dd><em>String</em>. An action message to be sent if the action key is pressed while a
suggestion is in focus. This is added to the
intent that that the system passes to your searchable activity (using the action
you've defined for the suggestion). To examine the string,
- use {@link android.content.Intent#getStringExtra
+ use {@link android.content.Intent#getStringExtra
getStringExtra(SearchManager.ACTION_MSG)}. This should only be used if all your
suggestions support this action key. If not all suggestions can handle the same action key, then
you must instead use the following {@code android:suggestActionMsgColumn} attribute.</dd>
- <dt><code>android:suggestActionMsgColumn</code></dt>
+ <dt><a name="suggestActionMsgColumn"></a><code>android:suggestActionMsgColumn</code></dt>
<dd><em>String</em>. The name of the column in your content provider that defines the
action message for this action key, which is to be sent if the user presses the action key while a
suggestion is in focus. This attribute lets you control the
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index e62c0ffc..c27047e 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -949,6 +949,9 @@
Recommending TV Content</a>
</li>
<li>
+ <a href="<?cs var:toroot ?>training/tv/discovery/searchable.html">
+ Making TV Apps Searchable</a>
+ <li>
<a href="<?cs var:toroot ?>training/tv/discovery/in-app-search.html">
Searching within TV Apps</a>
</li>
diff --git a/docs/html/training/tv/discovery/searchable.jd b/docs/html/training/tv/discovery/searchable.jd
new file mode 100644
index 0000000..5d3b9e3
--- /dev/null
+++ b/docs/html/training/tv/discovery/searchable.jd
@@ -0,0 +1,383 @@
+page.title=Making TV Apps Searchable
+page.tags="search","searchable"
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+ <h2>This lesson teaches you to</h2>
+ <ol>
+ <li><a href="#columns">Identify Columns</a></li>
+ <li><a href="#provide">Provide Search Suggestion Data</a></li>
+ <li><a href="#suggestions">Handle Search Suggestions</a></li>
+ <li><a href="#terms">Handle Search Terms</a></li>
+ <li><a href="#details">Deep Link to Your App in the Details Screen</a></li>
+ </ol>
+ <h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}guide/topics/search/index.html">Search</a></li>
+ <li><a href="{@docRoot}training/search/index.html">Adding Search Functionality</a></li>
+ </ul>
+ <h2>Try it out</h2>
+ <ul>
+ <li><a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android Leanback sample app</a></li>
+ </ul>
+</div>
+</div>
+
+<p>Android TV uses the Android <a href="{@docRoot}guide/topics/search/index.html">search interface</a>
+to retrieve content data from installed apps and deliver search results to the user. Your app's
+content data can be included with these results, to give the user instant access to the content in
+your app.</p>
+
+<p>Your app must provide Android TV with the data fields from which it generates suggested search
+results as the user enters characters in the search dialog. To do that, your app must implement a
+<a href="{@docRoot}guide/topics/providers/content-providers.html">Content Provider</a> that serves
+up the suggestions along with a <a href="{@docRoot}guide/topics/search/searchable-config.html">
+{@code searchable.xml}</a> configuration file that describes the content
+provider and other vital information for Android TV. You also need an activity that handles the
+intent that fires when the user selects a suggested search result. All of this is described in
+more detail in <a href="{@docRoot}guide/topics/search/adding-custom-suggestions.html">Adding Custom
+Suggestions</a>. Here are described the main points for Android TV apps.</p>
+
+<p>This lesson builds on your knowledge of using search in Android to show you how to make your app
+searchable in Android TV. Be sure you are familiar with the concepts explained in the
+<a href="{@docRoot}guide/topics/search/index.html">Search API guide</a> before following this lesson.
+See also the training <a href="{@docRoot}training/search/index.html">Adding Search Functionality</a>.</p>
+
+<p>This discussion describes some code from the
+<a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android Leanback sample app</a>,
+available on GitHub.</p>
+
+<h2 id="columns">Identify Columns</h2>
+
+<p>The {@link android.app.SearchManager} describes the data fields it expects by representing them as
+columns of an SQLite database. Regardless of your data's format, you must map your data fields to
+these columns, usually in the class that accessess your content data. For information about building
+a class that maps your existing data to the required fields, see
+<a href="{@docRoot}guide/topics/search/adding-custom-suggestions.html#SuggestionTable">
+Building a suggestion table</a>.</p>
+
+<p>The {@link android.app.SearchManager} class includes several columns for Android TV. Some of the
+more important columns are described below.</p>
+
+<table>
+<tr>
+ <th>Value</th>
+ <th>Description</th>
+</tr><tr>
+ <td>{@code SUGGEST_COLUMN_TEXT_1}</td>
+ <td>The name of your content <strong>(required)</strong></td>
+</tr><tr>
+ <td>{@code SUGGEST_COLUMN_TEXT_2}</td>
+ <td>A text description of your content</td>
+</tr><tr>
+ <td>{@code SUGGEST_COLUMN_RESULT_CARD_IMAGE}</td>
+ <td>An image/poster/cover for your content</td>
+</tr><tr>
+ <td>{@code SUGGEST_COLUMN_CONTENT_TYPE}</td>
+ <td>The MIME type of your media <strong>(required)</strong></td>
+</tr><tr>
+ <td>{@code SUGGEST_COLUMN_VIDEO_WIDTH}</td>
+ <td>The resolution width of your media</td>
+</tr><tr>
+ <td>{@code SUGGEST_COLUMN_VIDEO_HEIGHT}</td>
+ <td>The resolution height of your media</td>
+</tr><tr>
+ <td>{@code SUGGEST_COLUMN_PRODUCTION_YEAR}</td>
+ <td>The production year of your content <strong>(required)</strong></td>
+</tr><tr>
+ <td>{@code SUGGEST_COLUMN_DURATION}</td>
+ <td>The duration in milliseconds of your media</td>
+</tr>
+</table>
+
+<p>The search framework requires the following columns:</p>
+<ul>
+ <li>{@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}</li>
+ <li>{@link android.app.SearchManager#SUGGEST_COLUMN_CONTENT_TYPE}</li>
+ <li>{@link android.app.SearchManager#SUGGEST_COLUMN_PRODUCTION_YEAR}</li>
+</ul>
+
+<p>When the values of these columns for your content match the values for the same content from other
+providers found by Google servers, the system provides a
+<a href="{@docRoot}training/app-indexing/deep-linking.html">deep link</a> to your app in the details
+view for the content, along with links to the apps of other providers. This is discussed more in
+<a href="#details">Display Content in the Details Screen</a>, below.</p>
+
+<p>Your application's database class might define the columns as follows:</p>
+
+<p class="code-caption"><a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/java/com/example/android/tvleanback/VideoDatabase.java#L41" target="_blank">
+VideoDatabase.java</a></p>
+<pre>
+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;
+...
+</pre>
+
+<p>When you build the map from the {@link android.app.SearchManager} columns to your data fields, you
+must also specify the {@link android.provider.BaseColumns#_ID} to give each row a unique ID.</p>
+
+<p class="code-caption"><a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/java/com/example/android/tvleanback/VideoDatabase.java#L83" target="_blank">
+VideoDatabase.java</a></p>
+<pre>
+...
+ 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;
+ }
+...
+</pre>
+
+<p>In the example above, notice the mapping to the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID}
+field. This is the portion of the URI that points to the content unique to the data in this row —
+that is, the last part of the URI describing where the content is stored. The first part of the URI,
+when it is common to all of the rows in the table, is set in the
+<a href="{@docRoot}guide/topics/search/searchable-config.html"> {@code searchable.xml}</a> file as the
+<a href="{@docRoot}guide/topics/search/searchable-config.html#searchSuggestIntentData">
+{@code android:searchSuggestIntentData}</a> attribute, as described in
+<a href="#suggestions">Handle Search Suggestions</a>, below.
+
+<p>If the first part of the URI is different for each row in the
+table, you map that value with the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} field.
+When the user selects this content, the intent that fires provides the intent data from the
+combination of the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID}
+and either the {@code android:searchSuggestIntentData} attribute or the
+{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} field value.</p>
+
+<h2 id="provide">Provide Search Suggestion Data</h2>
+
+<p>Implement a <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Provider</a>
+to return search term suggestions to the Android TV search dialog. The system queries your content
+provider for suggestions by calling the {@link android.content.ContentProvider#query(android.net.Uri,
+java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) query()} method each time
+a letter is typed. In your implementation of {@link android.content.ContentProvider#query(android.net.Uri,
+java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) query()}, your content
+provider searches your suggestion data and returns a {@link android.database.Cursor} that points to
+the rows you have designated for suggestions.</p>
+
+<p class="code-caption"><a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/java/com/example/android/tvleanback/VideoContentProvider.java" target="_blank">
+VideoContentProvider.java</a></p>
+<pre>
+@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 mVideoDatabase.getWordMatch(query, columns);
+ }
+...
+</pre>
+
+<p>In your manifest file, the content provider receives special treatment. Rather than getting
+tagged as an activity, it is described as a
+<a href="{@docRoot}guide/topics/manifest/provider-element.html">{@code <provider>}</a>. The
+provider includes the {@code android:searchSuggestAuthority} attribute to tell the system the
+namespace of your content provider. Also, you must set its {@code android:exported} attribute to
+{@code "true"} so that the Android global search can use the results returned from it.</p>
+
+<p class="code-caption"><a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/AndroidManifest.xml" target="_blank">
+AndroidManifest.xml</a></p>
+<pre>
+<provider android:name="com.example.android.tvleanback.VideoContentProvider"
+ android:authorities="com.example.android.tvleanback"
+ android:exported="true" />
+</pre>
+
+<h2 id="suggestions">Handle Search Suggestions</h2>
+
+<p>Your app must include a <a href="{@docRoot}guide/topics/search/searchable-config.html">
+{@code res/xml/searchable.xml}</a> file to configure the search suggestions settings. It inlcudes
+the <a href="{@docRoot}guide/topics/search/searchable-config.html#searchSuggestAuthority">
+{@code android:searchSuggestAuthority}</a> attribute to tell the system the namespace of your
+content provider. This must match the string value you specify in the
+<a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">{@code android:authorities}</a>
+attribute of the <a href="{@docRoot}guide/topics/manifest/provider-element.html">{@code <provider>}
+</a> element in your {@code AndroidManifest.xml} file.</p>
+
+The <a href="{@docRoot}guide/topics/search/searchable-config.html">{@code searchable.xml}</a> file
+must also include the <a href="{@docRoot}guide/topics/search/searchable-config.html#searchSuggestIntentAction">
+{@code android:searchSuggestIntentAction}</a> with the value {@code "android.intent.action.VIEW"}
+to define the intent action for providing a custom suggestion. This is different from the intent
+action for providing a search term, explained below. See also,
+<a href="{@docRoot}guide/topics/search/adding-custom-suggestions.html#IntentAction">Declaring the
+intent action</a> for other ways to declare the intent action for suggestions.</p>
+
+<p>Along with the intent action, your app must provide the intent data, which you specify with the
+<a href="{@docRoot}guide/topics/search/searchable-config.html#searchSuggestIntentData">
+{@code android:searchSuggestIntentData}</a> attribute. This is the first part of the URI that points
+to the content. It describes the portion of the URI common to all rows in the mapping table for that
+content. The portion of the URI that is unique to each row is established with the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} field,
+as described above in <a href="#columns">Identify Columns</a>. See also,
+<a href="{@docRoot}guide/topics/search/adding-custom-suggestions.html#IntentData">
+Declaring the intent data</a> for other ways to declare the intent data for suggestions.</p>
+
+<p>Also, note the {@code android:searchSuggestSelection=" ?"} attribute which specifies the value passed
+as the {@code selection} parameter of the {@link android.content.ContentProvider#query(android.net.Uri,
+java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) query()} method where the
+question mark ({@code ?}) value is replaced with the query text.</p>
+
+<p>Finally, you must also include the <a href="{@docRoot}guide/topics/search/searchable-config.html#includeInGlobalSearch">
+{@code android:includeInGlobalSearch}</a> attribute with the value {@code "true"}. Here is an example
+<a href="{@docRoot}guide/topics/search/searchable-config.html">{@code searchable.xml}</a>
+file:</p>
+
+<p class="code-caption"><a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/res/xml/searchable.xml" target="_blank">
+Searchable.xml</a></p>
+<pre>
+<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>
+</pre>
+
+<h2 id="terms">Handle Search Terms</h2>
+
+<p>As soon as the search dialog has a word which matches the value in one of your app's columns
+(described in <a href="#identifying">Identifying Columns</a>, above), the system fires the
+{@link android.content.Intent#ACTION_SEARCH} intent. The activity in your app which handles that
+intent searches the repository for columns with the given word in their values, and returns a list
+of content items with those columns. In your {@code AndroidManifest.xml} file, you designate the
+activity which handles the {@link android.content.Intent#ACTION_SEARCH} intent like this:
+
+<p class="code-caption"><a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/AndroidManifest.xml" target="_blank">
+AndroidManifest.xml</a></p>
+<pre>
+...
+ <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" />
+...
+</pre>
+
+<p>The activity must also describe the searchable configuration with a reference to the
+<a href="{@docRoot}guide/topics/search/searchable-config.html">{@code searchable.xml}</a> file.
+To <a href="{@docRoot}guide/topics/search/search-dialog.html">use the global search dialog</a>,
+the manifest must describe which activity should receive search queries. The manifest must also
+describe the <a href="{@docRoot}guide/topics/manifest/provider-element.html">{@code <provider>}
+</a>element, exactly as it is described in the <a href="{@docRoot}guide/topics/search/searchable-config.html">
+{@code searchable.xml}</a> file.</p>
+
+<h2 id="details">Deep Link to Your App in the Details Screen</h2>
+
+<p>If you have set up the search configuration as described in <a href="#suggestions">Handle Search
+Suggestions</a> and mapped the {@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1},
+{@link android.app.SearchManager#SUGGEST_COLUMN_CONTENT_TYPE}, and
+{@link android.app.SearchManager#SUGGEST_COLUMN_PRODUCTION_YEAR} fields as described in
+<a href="#columns">Identify Columns</a>, a <a href="{@docRoot}training/app-indexing/deep-linking.html">
+deep link</a> to your content appears in the details screen that launches when the user selects a
+search result.</p>
+
+<p>When the user selects the link for your app, identified by the "Available On" button in the
+details screen, the system launches the activity which handles the {@link android.content.Intent#ACTION_VIEW}
+(set as <a href="{@docRoot}guide/topics/search/searchable-config.html#searchSuggestIntentAction">
+{@code android:searchSuggestIntentAction}</a> with the value {@code "android.intent.action.VIEW"} in
+the <a href="{@docRoot}guide/topics/search/searchable-config.html">{@code searchable.xml}</a> file).</p>
+
+<p>You can also set up a custom intent to launch your activity, and this is demonstrated in the
+<a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android Leanback
+sample app</a>. Note that the sample app launches its own <code>LeanbackDetailsFragment</code> to
+show the details for the selected media, but you should launch the activity that plays the media
+immediately to save the user another click or two.</p>
+
+
+
+
+
+