M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions

View File

@ -0,0 +1,748 @@
page.title=Adding Custom Suggestions
parent.title=Search
parent.link=index.html
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
<ol>
<li><a href="#TheBasics">The Basics</a></li>
<li><a href="#CustomSearchableConfiguration">Modifying the Searchable Configuration</a></li>
<li><a href="#CustomContentProvider">Creating a Content Provider</a>
<ol>
<li><a href="#HandlingSuggestionQuery">Handling a suggestion query</a></li>
<li><a href="#SuggestionTable">Building a suggestion table</a></li>
</ol>
</li>
<li><a href="#IntentForSuggestions">Declaring an Intent for Suggestions</a>
<ol>
<li><a href="#IntentAction">Declaring the Intent action</a></li>
<li><a href="#IntentData">Declaring the Intent data</a></li>
</ol>
</li>
<li><a href="#HandlingIntent">Handling the Intent</a></li>
<li><a href="#RewritingQueryText">Rewriting the Query Text</a></li>
<li><a href="#QSB">Exposing Search Suggestions to Quick Search Box</a></li>
</ol>
<h2>Key classes</h2>
<ol>
<li>{@link android.app.SearchManager}</li>
<li>{@link android.content.SearchRecentSuggestionsProvider}</li>
<li>{@link android.content.ContentProvider}</li>
</ol>
<h2>Related samples</h2>
<ol>
<li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable
Dictionary</a></li>
</ol>
<h2>See also</h2>
<ol>
<li><a href="searchable-config.html">Searchable Configuration</a></li>
<li><a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a></li>
</ol>
</div>
</div>
<p>When using the Android search dialog, you can provide custom search suggestions that are
created from data in your application. For example, if your application is a word
dictionary, you can suggest words from the
dictionary that match the text entered so far. These are the most valuable suggestions, because you
can effectively predict what the user wants and provide instant access to it. Figure 1 shows
an example of a search dialog with custom suggestions.</p>
<p>Once you provide custom suggestions, you can also make them available to the system-wide Quick
Search Box, providing access to your content from outside your application.</p>
<p>Before you begin with this guide to add custom suggestions, you need to have implemented the
Android search dialog for searches in your
application. If you haven't, see <a href="search-dialog.html">Using the Android Search
Dialog</a>.</p>
<h2 id="TheBasics">The Basics</h2>
<div class="figure" style="width:250px">
<img src="{@docRoot}images/search/search-suggest-custom.png" alt="" height="417" />
<p class="img-caption"><strong>Figure 1.</strong> Screenshot of a search dialog with custom
search suggestions.</p>
</div>
<p>When the user selects a custom suggestion, the Search Manager sends an {@link
android.content.Intent} to
your searchable Activity. Whereas a normal search query sends an Intent with the {@link
android.content.Intent#ACTION_SEARCH} action, you can instead define your custom suggestions to use
{@link android.content.Intent#ACTION_VIEW} (or any other Intent action), and also include data
that's relevant to the selected suggestion. Continuing
the dictionary example, when the user selects a suggestion, your application can immediately
open the definition for that word, instead of searching the dictionary for matches.</p>
<p>To provide custom suggestions, do the following:</p>
<ul>
<li>Implement a basic searchable Activity, as described in <a
href="search-dialog.html">Using the Android Search Dialog</a>.</li>
<li>Modify the searchable configuration with information about the content provider that
provides custom suggestions.</li>
<li>Build a table (such as in an {@link android.database.sqlite.SQLiteDatabase}) for your
suggestions and format the table with required columns.</li>
<li>Create a <a href="{@docRoot}guide/topics/providers/content-providers.html">Content
Provider</a> that has access to your suggestions table and declare the provider
in your manifest.</li>
<li>Declare the type of {@link android.content.Intent} to be sent when the user selects a
suggestion (including a custom action and custom data). </li>
</ul>
<p>Just like the Search Manager displays the search dialog, it also displays your search
suggestions. All you need is a content provider from which the Search Manager can retrieve your
suggestions. If you're not familiar with creating content
providers, read the <a href="{@docRoot}guide/topics/providers/content-providers.html">Content
Providers</a> developer guide before you continue.</p>
<p>When the Search Manager identifies that your Activity is searchable and provides search
suggestions, the following procedure takes place as soon as the user enters text into the
search dialog:</p>
<ol>
<li>Search Manager takes the search query text (whatever has been typed so far) and performs a
query to your content provider that manages your suggestions.</li>
<li>Your content provider returns a {@link android.database.Cursor} that points to all
suggestions that are relevant to the search query text.</li>
<li>Search Manager displays the list of suggestions provided by the Cursor.</li>
</ol>
<p>Once the custom suggestions are displayed, the following might happen:</p>
<ul>
<li>If the user types another key, or changes the query in any way, the above steps are repeated
and the suggestion list is updated as appropriate. </li>
<li>If the user executes the search, the suggestions are ignored and the search is delivered
to your searchable Activity using the normal {@link android.content.Intent#ACTION_SEARCH}
Intent.</li>
<li>If the user selects a suggestion, an Intent is sent to your searchable Activity, carrying a
custom action and custom data so that your application can open the suggested content.</li>
</ul>
<h2 id="CustomSearchableConfiguration">Modifying the searchable configuration</h2>
<p>To add support for custom suggestions, add the {@code android:searchSuggestAuthority} attribute
to the {@code &lt;searchable&gt;} element in your searchable configuration file. For example:</p>
<pre>
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_label"
android:hint="@string/search_hint"
<b>android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"</b>&gt;
&lt;/searchable&gt;
</pre>
<p>You might need some additional attributes, depending on the type of Intent you attach
to each suggestion and how you want to format queries to your content provider. The other optional
attributes are discussed in the following sections.</p>
<h2 id="CustomContentProvider">Creating a Content Provider</h2>
<p>Creating a content provider for custom suggestions requires previous knowledge about content
providers that's covered in the <a
href="{@docRoot}guide/topics/providers/content-providers.html">Content Provider</a> developer
guide. For the most part, a content provider for custom suggestions is the
same as any other content provider. However, for each suggestion you provide, the respective row in
the {@link android.database.Cursor} must include specific columns that the Search Manager
understands and uses to format the suggestions.</p>
<p>When the user starts typing into the search dialog, the Search Manager queries your content
provider for suggestions by calling {@link
android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} each time
a letter is typed. In your implementation of {@link
android.content.ContentProvider#query(Uri,String[],String,String[],String) query()}, your
content provider must search your suggestion data and return a {@link
android.database.Cursor} that points to the rows you have determined to be good suggestions.</p>
<p>Details about creating a content provider for custom suggestions are discussed in the following
two sections:</p>
<dl>
<dt><a href="#HandlingSuggestionQuery">Handling the suggestion query</a></dt>
<dd>How the Search Manager sends requests to your content provider and how to handle them</dd>
<dt><a href="#SuggestionTable">Building a suggestion table</a></dt>
<dd>How to define the columns that the Search Manager expects in the {@link
android.database.Cursor} returned with each query</dd>
</dl>
<h3 id="HandlingSuggestionQuery">Handling the suggestion query</h3>
<p>When the Search Manager requests suggestions from your content provider, it calls your content
provider's {@link android.content.ContentProvider#query(Uri,String[],String,String[],String)
query()} method. You must
implement this method to search your suggestion data and return a
{@link android.database.Cursor} pointing to the suggestions you deem relevant.</p>
<p>Here's a summary of the parameters that the Search Manager passes to your {@link
android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method
(listed in order):</p>
<dl>
<dt><code>uri</code></dt>
<dd>Always a content {@link android.net.Uri}, formatted as:
<pre class="no-pretty-print">
content://<em>your.authority</em>/<em>optional.suggest.path</em>/<em>{@link
android.app.SearchManager#SUGGEST_URI_PATH_QUERY}</em>
</pre>
<p>The default behavior is for Search Manager to pass this URI and append it with the query text.
For example:</p>
<pre class="no-pretty-print">
content://<em>your.authority</em>/<em>optional.suggest.path</em>/<em>{@link
android.app.SearchManager#SUGGEST_URI_PATH_QUERY}</em>/puppies
</pre>
<p>The query text on the end is encoded using URI encoding rules, so you might need to decode
it before performing a search.</p>
<p>The <em>{@code optional.suggest.path}</em> portion is only included in the URI if you have set
such a path in your searchable configuration file with the {@code android:searchSuggestPath}
attribute. This is only needed if you use the same content provider for multiple searchable
activities, in which case, you need to disambiguate the source of the suggestion query.</p>
<p class="note"><strong>Note:</strong> {@link
android.app.SearchManager#SUGGEST_URI_PATH_QUERY} is not the literal
string provided in the URI, but a constant that you should use if you need to refer to this
path.</p>
</dd>
<dt><code>projection</code></dt>
<dd>Always null</dd>
<dt><code>selection</code></dt>
<dd>The value provided in the {@code android:searchSuggestSelection} attribute of
your searchable configuration file, or null if you have not declared the {@code
android:searchSuggestSelection} attribute. More about using this to <a href="#GetTheQuery">get the
query</a> below.</dd>
<dt><code>selectionArgs</code></dt>
<dd>Contains the search query as the first (and only) element of the array if you have
declared the {@code android:searchSuggestSelection} attribute in your searchable configuration. If
you have not declared {@code android:searchSuggestSelection}, then this parameter is null. More
about using this to <a href="#GetTheQuery">get the query</a> below.</dd>
<dt><code>sortOrder</code></dt>
<dd>Always null</dd>
</dl>
<p>The Search Manager can send you the search query text in two ways. The
default manner is for the query text to be included as the last path of the content
URI passed in the {@code uri} parameter. However, if you include a selection value in your
searchable configuration's {@code
android:searchSuggestSelection} attribute, then the query text is instead passed as the first
element of the {@code selectionArgs} string array. Both options are summarized next.</p>
<h4 id="GetTheQueryUri">Get the query in the Uri</h4>
<p>By default, the query is appended as the last segment of the {@code uri}
parameter (a {@link android.net.Uri} object). To retrieve the query text in this case, simply use
{@link android.net.Uri#getLastPathSegment()}. For example:</p>
<pre>
String query = uri.getLastPathSegment().toLowerCase();
</pre>
<p>This returns the last segment of the {@link android.net.Uri}, which is the query text entered in
the search dialog.</p>
<h4 id="GetTheQuery">Get the query in the selection arguments</h4>
<p>Instead of using the URI, you might decide it makes more sense for your {@link
android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method to
receive everything it needs to perform the look-up and you want the
{@code selection} and {@code selectionArgs} parameters to carry the appropriate values. In such a
case, add the {@code android:searchSuggestSelection} attribute to your searchable configuration with
your SQLite selection string. In the selection string, include a question mark ("?") as
a placeholder for the actual search query. The Search Manager calls {@link
android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} with the
selection string as the {@code selection} parameter and the search query as the first
element in the {@code selectionArgs} array.</p>
<p>For example, here's how you might form the {@code android:searchSuggestSelection} attribute to
create a full-text search statement:</p>
<pre>
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_label"
android:hint="@string/search_hint"
android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"
android:searchSuggestIntentAction="android.Intent.action.VIEW"
<b>android:searchSuggestSelection="word MATCH ?"</b>&gt;
&lt;/searchable&gt;
</pre>
<p>With this configuration, your {@link
android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method
delivers the {@code selection} parameter as "word MATCH ?" and the {@code selectionArgs}
parameter as whatever the user entered in the search dialog. When you pass these to an SQLite
{@link android.database.sqlite.SQLiteDatabase#query(String,String[],String,String[],String,String,
String) query()} method, as their respective arguments, they are synthesized together (the
question mark is replaced with the query
text). If you chose to receive suggestion queries this way and need to add wildcards to
the query text, append (and/or prefix) them to the {@code selectionArgs}
parameter, because this value is wrapped in quotes and inserted in place of the
question mark.</p>
<p>Another new attribute in the example above is {@code android:searchSuggestIntentAction}, which
defines the Intent action sent with each Intent when the user selects a suggestion. It is
discussed further in the section about <a href="#IntentForSuggestions">Declaring an Intent for
suggestions</a>.</p>
<p class="note"><strong>Tip:</strong> If you don't want to define a selection clause in
the {@code android:searchSuggestSelection} attribute, but would still like to receive the query
text in the {@code selectionArgs} parameter, simply provide a non-null value for the {@code
android:searchSuggestSelection} attribute. This triggers the query to be passed in {@code
selectionArgs} and you can ignore the {@code selection} parameter. In this way, you can instead
define the actual selection clause at a lower level so that your content provider doesn't have to
handle it.</p>
<h3 id="SuggestionTable">Building a suggestion table</h3>
<div class="sidebox-wrapper">
<div class="sidebox">
<h2>Creating a Cursor without a table</h2>
<p>If your search suggestions are not stored in a table format (such as an SQLite table) using the
columns required by the
Search Manager, then you can search your suggestion data for matches and then format them
into the necessary table on each request. To do so, create a {@link android.database.MatrixCursor}
using the required column names and then add a row for each suggestion using {@link
android.database.MatrixCursor#addRow(Object[])}. Return the final product from your Content
Provider's {@link
android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method.</p>
</div>
</div>
<p>When you return suggestions to the Search Manager with a {@link android.database.Cursor}, the
Search Manager expects specific columns in each row. So, regardless of whether you
decide to store
your suggestion data in an SQLite database on the device, a database on a web server, or another
format on the device or web, you must format the suggestions as rows in a table and
present them with a {@link android.database.Cursor}. The Search
Manager understands several columns, but only two are required:</p>
<dl>
<dt>{@link android.provider.BaseColumns#_ID}</dt>
<dd>A unique integer row ID for each suggestion. The search dialog requires this in order
to present suggestions in a ListView.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}</dt>
<dd>The string that is presented as a suggestion.</dd>
</dl>
<p>The following columns are all optional (and most are discussed further in the following
sections):</p>
<dl>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_2}</dt>
<dd>A string. If your Cursor includes this column, then all suggestions are provided in a
two-line format. The string in this column is displayed as a second, smaller line of text below the
primary suggestion text. It can be null or empty to indicate no secondary text.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_ICON_1}</dt>
<dd>A drawable resource, content, or file URI string. If your Cursor includes this column, then
all suggestions are provided in an icon-plus-text format with the drawable icon on the left side.
This can be null or zero to indicate no icon in this row.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_ICON_2}</dt>
<dd>A drawable resource, content, or file URI string. If your Cursor includes this column, then
all suggestions are provided in an icon-plus-text format with the icon on the right side. This can
be null or zero to indicate no icon in this row.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION}</dt>
<dd>An Intent action string. If this column exists and contains a value at the given row, the
action defined here is used when forming the suggestion's Intent. If the element is not
provided, the action is taken from the {@code android:searchSuggestIntentAction} field in your
searchable configuration. If your action is the same for all
suggestions, it is more efficient to specify the action using {@code
android:searchSuggestIntentAction} and omit this column.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA}</dt>
<dd>A data URI string. If this column exists and contains a value at the given row, this is the
data that is used when forming the suggestion's Intent. If the element is not provided, the data is
taken from the {@code android:searchSuggestIntentData} field in your searchable configuration. If
neither source is provided,
the Intent's data field is null. If your data is the same for all suggestions, or can be
described using a constant part and a specific ID, it is more efficient to specify it using {@code
android:searchSuggestIntentData} and omit this column.
</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID}</dt>
<dd>A URI path string. If this column exists and contains a value at the given row, then "/" and
this value is appended to the data field in the Intent. This should only be used if the data field
specified
by the {@code android:searchSuggestIntentData} attribute in the searchable configuration has already
been set to an appropriate base string.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_EXTRA_DATA}</dt>
<dd>Arbitrary data. If this column exists and contains a value at a given row, this is the
<em>extra</em> data used when forming the suggestion's Intent. If not provided, the
Intent's extra data field is null. This column allows suggestions to provide additional data that is
included as an extra in the Intent's {@link android.app.SearchManager#EXTRA_DATA_KEY} key.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_QUERY}</dt>
<dd>If this column exists and this element exists at the given row, this is the data that is
used when forming the suggestion's query, included as an extra in the Intent's {@link
android.app.SearchManager#QUERY} key. Required if suggestion's action is {@link
android.content.Intent#ACTION_SEARCH}, optional otherwise.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID}</dt>
<dd>Only used when providing suggestions for Quick Search Box. This column indicates
whether a search suggestion should be stored as a
shortcut and whether it should be validated. Shortcuts are usually formed when the user clicks a
suggestion from Quick Search Box. If missing, the result is stored as a shortcut and never
refreshed. If set to {@link android.app.SearchManager#SUGGEST_NEVER_MAKE_SHORTCUT}, the result is
not stored as a shortcut.
Otherwise, the shortcut ID is used to check back for an up to date suggestion using
{@link android.app.SearchManager#SUGGEST_URI_PATH_SHORTCUT}.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING}</dt>
<dd>Only used when providing suggestions for Quick Search Box. This column specifies that
a spinner should be shown instead of an icon from {@link
android.app.SearchManager#SUGGEST_COLUMN_ICON_2}
while the shortcut of this suggestion is being refreshed in Quick Search Box.</dd>
</dl>
<p>Some of these columns are discussed more in the following sections.</p>
<h2 id="IntentForSuggestions">Declaring an Intent for suggestions</h2>
<p>When the user selects a suggestion from the list that appears below the search dialog, the Search
Manager sends a custom {@link android.content.Intent} to your searchable Activity. You must define
the action and data for the Intent.</p>
<h3 id="IntentAction">Declaring the Intent action</h3>
<p>The most common Intent action for a custom suggestion is {@link
android.content.Intent#ACTION_VIEW}, which is appropriate when
you want to open something, like the definition for a word, a person's contact information, or a web
page. However, the Intent action can be any other action and can even be different for each
suggestion.</p>
<p>Depending on whether you want all suggestions to use the same Intent action, you
can define the action in two ways:</p>
<ol type="a">
<li>Use the {@code android:searchSuggestIntentAction} attribute of your searchable configuration
file to define the action for all suggestions. <p>For example:</p>
<pre>
&lt;?xml version="1.0" encoding="utf-8"?>
&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_label"
android:hint="@string/search_hint"
android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"
<b>android:searchSuggestIntentAction="android.Intent.action.VIEW"</b> >
&lt;/searchable>
</pre>
</li>
<li>Use the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column to define the
action for individual suggestions.
<p>Add the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column to
your suggestions table and, for each suggestion, place in it the action to use (such as
{@code "android.Intent.action.VIEW"}).</p>
</li>
</ol>
<p>You can also combine these two techniques. For instance, you can include the {@code
android:searchSuggestIntentAction} attribute with an action to be used with all suggestions by
default, then override this action for some suggestions by declaring a different action in the
{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column. If you do not include
a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column, then the
Intent provided in the {@code android:searchSuggestIntentAction} attribute is used.</p>
<p class="note"><strong>Note</strong>: If you do not include the
{@code android:searchSuggestIntentAction} attribute in your searchable configuration, then you
<em>must</em> include a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION}
column for every suggestion, or the Intent will fail.</p>
<h3 id="IntentData">Declaring Intent data</h3>
<p>When the user selects a suggestion, your searchable Activity receives the Intent with the
action you've defined (as discussed in the previous section), but the Intent must also carry
data in order for your Activity to identify which suggestion was selected. Specifically,
the data should be something unique for each suggestion, such as the row ID for the suggestion in
your SQLite table. When the Intent is received,
you can retrieve the attached data with {@link android.content.Intent#getData()} or {@link
android.content.Intent#getDataString()}.</p>
<p>You can define the data included with the Intent in two ways:</p>
<ol type="a">
<li>Define the data for each suggestion inside the {@link
android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column of your suggestions table.
<p>Provide all necessary data information for each Intent in the suggestions table by including the
{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column and then populating it with
unique data for each row. The data from this column is attached to the Intent exactly as you
define it in this column. You can then retrieve it with with {@link
android.content.Intent#getData()} or {@link android.content.Intent#getDataString()}.</p>
<p class="note"><strong>Tip</strong>: It's usually easiest to use the table's row ID as the
Intent data, because it's always unique. And the easiest way to do that is by using the
{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column name as an alias for the row ID
column. See the <a
href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable Dictionary sample
app</a> for an example in which {@link android.database.sqlite.SQLiteQueryBuilder} creates a
projection map of column names to aliases.</p>
</li>
<li>Fragment a data URI into two pieces: the portion common to all suggestions and the portion
unique to each suggestion. Place these parts into the {@code android:searchSuggestIntentData}
attribute of the searchable configuration and the {@link
android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column of your
suggestions table, respectively.
<p>Declare the piece of the URI that is common to all suggestions in the {@code
android:searchSuggestIntentData} attribute of your searchable configuration. For example:</p>
<pre>
&lt;?xml version="1.0" encoding="utf-8"?>
&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_label"
android:hint="@string/search_hint"
android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"
android:searchSuggestIntentAction="android.Intent.action.VIEW"
<b>android:searchSuggestIntentData="content://com.example/datatable"</b> >
&lt;/searchable>
</pre>
<p>Then include the final path for each suggestion (the unique part) in the {@link
android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID}
column of your suggestions table. When the user selects a suggestion, the Search Manager takes
the string from {@code android:searchSuggestIntentData}, appends a slash ("/") and then adds the
respective value from the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column to
form a complete content URI. You can then retrieve the {@link android.net.Uri} with with {@link
android.content.Intent#getData()}.</p>
</li>
</ol>
<h4>Add more data</h4>
<p>If you need to express even more information with your Intent, you can add another table column,
{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_EXTRA_DATA}, which can store additional
information about the suggestion. The data saved in this column is placed in {@link
android.app.SearchManager#EXTRA_DATA_KEY} of the Intent's extra Bundle.</p>
<h2 id="HandlingIntent">Handling the Intent</h2>
<p>Now that your search dialog provides custom search suggestions with custom Intents, you
need your searchable Activity to handle these Intents when the user selects a
suggestion. This is in addition to handling the {@link
android.content.Intent#ACTION_SEARCH} Intent, which your searchable Activity already does.
Here's an example of how you can handle the Intents during your Activity {@link
android.app.Activity#onCreate(Bundle) onCreate()} callback:</p>
<pre>
Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
// Handle the normal search query case
String query = intent.getStringExtra(SearchManager.QUERY);
doSearch(query);
} else if (Intent.ACTION_VIEW.equals(intent.getAction())) {
// Handle a suggestions click (because the suggestions all use ACTION_VIEW)
Uri data = intent.getData();
showResult(data);
}
</pre>
<p>In this example, the Intent action is {@link
android.content.Intent#ACTION_VIEW} and the data carries a complete URI pointing to the suggested
item, as synthesized by the {@code android:searchSuggestIntentData} string and {@link
android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column. The URI is then passed to the local
{@code showResult()} method that queries the content provider for the item specified by the URI.</p>
<p class="note"><strong>Note:</strong> You do <em>not</em> need to add an Intent filter to your
Android manifest file for the Intent action you defined with the {@code
android:searchSuggestIntentAction} attribute or {@link
android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column. The Search Manager opens your
searchable Activity by name to deliver the suggestion's Intent, so the Activity does not need to
declare the accepted action.</p>
<h2 id="RewritingQueryText">Rewriting the query text</h2>
<p>If the user navigates through the suggestions list using the directional controls (trackball or
d-pad), the text in the search dialog won't change, by default. However, you can temporarily rewrite
the user's query text as it appears in the text box with
a query that matches the suggestion currently in focus. This enables the user to see what query is
being suggested (if appropriate) and then select the search box and edit the query before
dispatching it as a search.</p>
<p>You can rewrite the query text in the following ways:</p>
<ol type="a">
<li>Add the {@code android:searchMode} attribute to your searchable configuration with the
"queryRewriteFromText" value. In this case, the content from the suggestion's {@link
android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}
column is used to rewrite the query text.</li>
<li>Add the {@code android:searchMode} attribute to your searchable configuration with the
"queryRewriteFromData" value. In this case, the content from the suggestion's
{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column is used to rewrite the
query text. This should only
be used with URI's or other data formats that are intended to be user-visible, such as HTTP URLs.
Internal URI schemes should not be used to rewrite the query in this way.</li>
<li>Provide a unique query text string in the {@link
android.app.SearchManager#SUGGEST_COLUMN_QUERY} column of your suggestions table. If this column is
present and contains a value for the current suggestion, it is used to rewrite the query text
(and override either of the previous implementations).</li>
</ol>
<h2 id="QSB">Exposing search suggestions to Quick Search Box</h2>
<p>Once you configure your application to provide custom search suggestions, making them available
to the globally accessible Quick Search Box is as easy as modifying your searchable configuration to
include {@code android:includeInGlobalSearch} as "true".</p>
<p>The only scenario in which additional work is necessary is when your content provider demands a
read permission. In which case, you need to add a special
{@code &lt;path-permission&gt;} element for the provider to grant Quick Search Box read access to
your content provider. For example:</p>
<pre>
&lt;provider android:name="MySuggestionProvider"
android:authorities="com.example.MyCustomSuggestionProvider"
android:readPermission="com.example.provider.READ_MY_DATA"
android:writePermission="com.example.provider.WRITE_MY_DATA"&gt;
&lt;path-permission android:pathPrefix="/search_suggest_query"
android:readPermission="android.permission.GLOBAL_SEARCH" /&gt;
&lt;/provider&gt;
</pre>
<p>In this example, the provider restricts read and write access to the content. The
{@code &lt;path-permission>} element amends the restriction by granting read access to content
inside the {@code "/search_suggest_query"} path prefix when the {@code
"android.permission.GLOBAL_SEARCH"} permission exists. This grants access to Quick Search Box
so that it may query your content provider for suggestions.</p>
<p>If your content provider does not enforce read permissions, then Quick Search Box can read
it by default.</p>
<h3 id="EnablingSuggestions">Enabling suggestions on a device</h3>
<p>When your application is configured to provide suggestions in Quick Search Box, it is not
actually enabled to provide suggestions in Quick Search Box, by default. It is the user's choice
whether to include suggestions from your application in the Quick Search Box. To enable search
suggestions from your application, the user must open "Searchable items" (in Settings > Search) and
enable your application as a searchable item.</p>
<p>Each application that is available to Quick Search Box has an entry in the Searchable items
settings page. The entry includes the name of the application and a short description of what
content can be searched from the application and made available for suggestions in Quick Search Box.
To define the description text for your searchable application, add the {@code
android:searchSettingsDescription} attribute to your searchable configuration. For example:</p>
<pre>
&lt;?xml version="1.0" encoding="utf-8"?>
&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_label"
android:hint="@string/search_hint"
android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"
android:searchSuggestIntentAction="android.Intent.action.VIEW"
android:includeInGlobalSearch="true"
<b>android:searchSettingsDescription="@string/search_description"</b> >
&lt;/searchable>
</pre>
<p>The string for {@code android:searchSettingsDescription} should be as concise as possible and
state the content that is searchable. For example, "Artists, albums, and tracks" for a music
application, or "Saved notes" for a notepad application. Providing this description is important so
the user knows what kind of suggestions are provided. You should always include this attribute
when {@code android:includeInGlobalSearch} is "true".</p>
<p>Remember that the user must visit the settings menu to enable search suggestions for your
application before your search suggestions appear in Quick Search Box. As such, if search is an
important aspect of your application, then you might want to consider a way to convey that to
your users &mdash; you might provide a note the first time they launch the app that instructs
them how to enable search suggestions for Quick Search Box.</p>
<h3 id="ManagingShortcuts">Managing Quick Search Box suggestion shortcuts</h3>
<p>Suggestions that the user selects from Quick Search Box can be automatically made into shortcuts.
These are suggestions that the Search Manager has copied from your content provider so it can
quickly access the suggestion without the need to re-query your content provider. </p>
<p>By default, this is enabled for all suggestions retrieved by Quick Search Box, but if your
suggestion data changes over time, then you can request that the shortcuts be refreshed. For
instance, if your suggestions refer to dynamic data, such as a contact's presence status, then you
should request that the suggestion shortcuts be refreshed when shown to the user. To do so,
include the {@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} in your suggestions table.
Using this column, you can
configure the shortcut behavior for each suggestion in one of the following ways:</p>
<ol type="a">
<li>Have Quick Search Box re-query your content provider for a fresh version of the suggestion
shortcut.
<p>Provide a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} column
and the suggestion is
re-queried for a fresh version each time the shortcut is displayed. The shortcut
is quickly displayed with whatever data was most recently available until the refresh query
returns, at which point the suggestion is refreshed with the new information. The
refresh query is sent to your content provider with a URI path of {@link
android.app.SearchManager#SUGGEST_URI_PATH_SHORTCUT}
(instead of {@link android.app.SearchManager#SUGGEST_URI_PATH_QUERY}).</p>
<p>The {@link android.database.Cursor} you return should contain one suggestion using the
same columns as the original suggestion, or be empty, indicating that the shortcut is no
longer valid (in which case, the suggestion disappears and the shortcut is removed).</p>
<p>If a suggestion refers to data that could take longer to refresh, such as a network-based
refresh, you can also add the {@link
android.app.SearchManager#SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING} column to your suggestions
table with a value
of "true" in order to show a progress spinner for the right hand icon until the refresh is complete.
Any value other than "true" does not show the progress spinner.</p>
</li>
<li>Prevent the suggestion from being copied into a shortcut at all.
<p>Provide a value of {@link android.app.SearchManager#SUGGEST_NEVER_MAKE_SHORTCUT} in the
{@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} column. In
this case, the suggestion is never copied into a shortcut. This should only be necessary if you
absolutely do not want the previously copied suggestion to appear. (Recall that if you
provide a normal value for the column, then the suggestion shortcut appears only until the
refresh query returns.)</p></li>
<li>Allow the default shortcut behavior to apply.
<p>Leave the {@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} empty for each
suggestion that will not change and can be saved as a shortcut.</p></li>
</ol>
<p>If none of your suggestions ever change, then you do not need the
{@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} column at all.</p>
<p class="note"><strong>Note</strong>: Quick Search Box ultimately decides whether or not to create
a shortcut for a suggestion, considering these values as a strong request from your
application&mdash;there is no guarantee that the behavior you have requested for your suggestion
shortcuts will be honored.</p>
<h3 id="AboutRanking">About Quick Search Box suggestion ranking</h3>
<p>Once you make your application's search suggestions available to Quick Search Box, the Quick
Search Box ranking determines how the suggestions are surfaced to the user for a particular query.
This might depend on how many other apps have results for that query, and how often the user has
selected your results compared to those from other apps. There is no guarantee about how your
suggestions are ranked, or whether your app's suggestions show at all for a given query. In
general, you can expect that providing quality results increases the likelihood that your app's
suggestions are provided in a prominent position and apps that provide low quality suggestions
are more likely to be ranked lower or not displayed.</p>
<div class="special">
<p>See the <a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable
Dictionary sample app</a> for a complete demonstration of custom search suggestions.</p>
</div>

View File

@ -0,0 +1,235 @@
page.title=Adding Recent Query Suggestions
parent.title=Search
parent.link=index.html
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
<ol>
<li><a href="#TheBasics">The Basics</a></li>
<li><a href="#RecentQueryContentProvider">Creating a Content Provider</a></li>
<li><a href="#RecentQuerySearchableConfiguration">Modifying the Searchable
Configuration</a></li>
<li><a href="#SavingQueries">Saving Queries</a></li>
<li><a href="#ClearingSuggestionData">Clearing the Suggestion Data</a></li>
</ol>
<h2>Key classes</h2>
<ol>
<li>{@link android.provider.SearchRecentSuggestions}</li>
<li>{@link android.content.SearchRecentSuggestionsProvider}</li>
</ol>
<h2>See also</h2>
<ol>
<li><a href="searchable-config.html">Searchable Configuration</a></li>
</ol>
</div>
</div>
<p>When using the Android search dialog, you can provide search suggestions based on recent search
queries. For example, if a user previously searched for "puppies," then that query appears as a
suggestion once he or she begins typing the same query. Figure 1 shows an example of a search dialog
with recent query suggestions.</p>
<p>Before you begin, you need to implement the search dialog for basic searches in your application.
If you haven't, see <a href="search-dialog.html">Using the Android Search Dialog</a>.</p>
<h2 id="TheBasics">The Basics</h2>
<div class="figure" style="width:250px">
<img src="{@docRoot}images/search/search-suggest-recent-queries.png" alt="" height="417" />
<p class="img-caption"><strong>Figure 1.</strong> Screenshot of a search dialog with recent query
suggestions.</p>
</div>
<p>Recent query suggestions are simply saved searches. When the user selects one of
the suggestions, your searchable Activity receives a {@link
android.content.Intent#ACTION_SEARCH} Intent with the suggestion as the search query, which your
searchable Activity already handles (as described in <a href="search-dialog.html">Using the Android
Search Dialog</a>).</p>
<p>To provide recent queries suggestions, you need to:</p>
<ul>
<li>Implement a searchable Activity, <a
href="{@docRoot}guide/topics/search/search-dialog.html">using the Android Search Dialog</a>.</li>
<li>Create a content provider that extends {@link
android.content.SearchRecentSuggestionsProvider} and declare it in your application manifest.</li>
<li>Modify the searchable configuration with information about the content provider that
provides search suggestions.</li>
<li>Save queries to your content provider each time a search is executed.</li>
</ul>
<p>Just as the Search Manager displays the search dialog, it also displays the
search suggestions. All you need to do is provide a source from which the suggestions can be
retrieved.</p>
<p>When the Search Manager identifies that your Activity is searchable and provides search
suggestions, the following procedure takes place as soon as the user types into the search
dialog:</p>
<ol>
<li>Search Manager takes the search query text (whatever has been typed so far) and performs a
query to the content provider that contains your suggestions.</li>
<li>Your content provider returns a {@link android.database.Cursor} that points to all
suggestions that match the search query text.</li>
<li>Search Manager displays the list of suggestions provided by the Cursor.</li>
</ol>
<p>Once the recent query suggestions are displayed, the following might happen:</p>
<ul>
<li>If the user types another key, or changes the query in any way, the aforementioned steps are
repeated and the suggestion list is updated.</li>
<li>If the user executes the search, the suggestions are ignored and the search is delivered
to your searchable Activity using the normal {@link android.content.Intent#ACTION_SEARCH}
Intent.</li>
<li>If the user selects a suggestion, an
{@link android.content.Intent#ACTION_SEARCH} Intent is delivered to your searchable Activity using
the suggested text as the query.</li>
</ul>
<p>The {@link android.content.SearchRecentSuggestionsProvider} class that
you extend for your content provider automatically does the work described above, so there's
actually very little code to write.</p>
<h2 id="RecentQueryContentProvider">Creating a Content Provider</h2>
<p>The content provider that you need for recent query suggestions must be an implementation
of {@link android.content.SearchRecentSuggestionsProvider}. This class does practically everything
for you. All you have to do is write a class constructor that executes one line of code.</p>
<p>For example, here's a complete implementation of a content provider for recent query
suggestions:</p>
<pre>
public class MySuggestionProvider extends SearchRecentSuggestionsProvider {
public final static String AUTHORITY = "com.example.MySuggestionProvider";
public final static int MODE = DATABASE_MODE_QUERIES;
public MySuggestionProvider() {
setupSuggestions(AUTHORITY, MODE);
}
}
</pre>
<p>The call to {@link android.content.SearchRecentSuggestionsProvider#setupSuggestions(String,int)
setupSuggestions()} passes the name of the search authority and a
database mode. The search authority can be any unique string, but the best practice is to use a
fully qualified name for your content provider
(package name followed by the provider's class name; for example,
"com.example.MySuggestionProvider"). The database mode must include {@link
android.content.SearchRecentSuggestionsProvider#DATABASE_MODE_QUERIES} and can optionally include
{@link
android.content.SearchRecentSuggestionsProvider#DATABASE_MODE_2LINES}, which adds another column
to the suggestions table that allows you to provide a second line of text with each suggestion. For
example, if you want to provide two lines in each suggestion:</p>
<pre>
public final static int MODE = DATABASE_MODE_QUERIES | DATABASE_MODE_2LINES;
</pre>
<p>Now declare the content provider in your application manifest with the same authority
string used in your {@link android.content.SearchRecentSuggestionsProvider} class (and in the
searchable configuration). For example:</p>
<pre>
&lt;application>
&lt;provider android:name=".MySuggestionProvider"
android:authorities="com.example.MySuggestionProvider" />
...
&lt;/application>
</pre>
<h2 id="RecentQuerySearchableConfiguration">Modifying the Searchable Configuration</h2>
<p>To configure your search dialog to use your suggestions provider, you need to add
the {@code android:searchSuggestAuthority} and {@code android:searchSuggestSelection} attributes to
the {@code &lt;searchable&gt;} element in your searchable configuration file. For example:</p>
<pre>
&lt;?xml version="1.0" encoding="utf-8"?>
&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_label"
android:hint="@string/search_hint"
<b>android:searchSuggestAuthority="com.example.MySuggestionProvider"
android:searchSuggestSelection=" ?"</b> >
&lt;/searchable>
</pre>
<p>The value for {@code android:searchSuggestAuthority} should be a fully qualified name for
your content provider that exactly matches the authority used in the content provider (the {@code
AUTHORITY} string in the above example).
</p>
<p>The value for {@code android:searchSuggestSelection} must be a single question mark, preceded by
a space ({@code " ?"}), which is simply a placeholder for the SQLite selection argument (which is
automatically replaced by the query text entered by the user).</p>
<h2 id="SavingQueries">Saving Queries</h2>
<p>To populate your collection of recent queries, add each query
received by your searchable Activity to your {@link
android.content.SearchRecentSuggestionsProvider}. To do this, create an instance of {@link
android.provider.SearchRecentSuggestions} and call {@link
android.provider.SearchRecentSuggestions#saveRecentQuery(String,String) saveRecentQuery()} each time
your searchable Activity receives a query. For example, here's how you can save the query during
your Activity's {@link android.app.Activity#onCreate(Bundle) onCreate()} method:</p>
<pre>
&#64;Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent Intent = getIntent();
if (Intent.ACTION_SEARCH.equals(Intent .getAction())) {
String query = Intent .getStringExtra(SearchManager.QUERY);
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
MySuggestionProvider.AUTHORITY, MySuggestionProvider.MODE);
suggestions.saveRecentQuery(query, null);
}
}
</pre>
<p>The {@link android.content.SearchRecentSuggestionsProvider} constructor requires the
same authority and database mode declared by your content provider.</p>
<p>The {@link android.provider.SearchRecentSuggestions#saveRecentQuery(String,String)
saveRecentQuery()} method takes
the search query string as the first parameter and, optionally, a second string to include as the
second line of the suggestion (or null). The second parameter is only used if you've enabled
two-line mode for the search suggestions with {@link
android.content.SearchRecentSuggestionsProvider#DATABASE_MODE_2LINES}. If you have enabled
two-line mode, then the query text is also matched against this second line when the Search Manager
looks for matching suggestions.</p>
<h2 id="ClearingSuggestionData">Clearing the Suggestion Data</h2>
<p>To protect the user's privacy, you should always provide a way for the user to clear the recent
query suggestions. To clear the query history, call {@link
android.provider.SearchRecentSuggestions#clearHistory()}. For example:</p>
<pre>
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
HelloSuggestionProvider.AUTHORITY, HelloSuggestionProvider.MODE);
suggestions.clearHistory();
</pre>
<p>Execute this from your choice of a "Clear Search History" menu item,
preference item, or button. You should also provide a confirmation dialog to
verify that the user wants to delete their search history.</p>

View File

@ -0,0 +1,109 @@
page.title=Search
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>Topics</h2>
<ol>
<li><a href="search-dialog.html">Using the Android Search Dialog</a></li>
<li><a href="adding-recent-query-suggestions.html">Adding Recent Query Suggestions</a></li>
<li><a href="adding-custom-suggestions.html">Adding Custom Suggestions</a></li>
</ol>
<h2>Reference</h2>
<ol>
<li><a href="searchable-config.html">Searchable Configuration</a></li>
</ol>
<h2>Related samples</h2>
<ol>
<li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable
Dictionary</a></li>
</ol>
</div>
</div>
<p>Search is a core user feature on Android. Users should be able
to search any data that is available to them, whether the content is located on the device or
the Internet. The search experience should be seamless and consistent across the entire
system, which is why Android provides a search framework to help you provide users with
a familiar search dialog and a great search experience.</p>
<div class="figure" style="width:250px">
<img src="{@docRoot}images/search/search-suggest-custom.png" alt="" height="417" />
<p class="img-caption"><strong>Figure 1.</strong> Screenshot of a search dialog with custom
search suggestions.</p>
</div>
<p>Android's search framework provides a user interface in which users can perform a search and
an interaction layer that communicates with your application, so you don't have to build
your own search Activity. Instead, a search dialog appears at the top of the screen at the user's
command without interrupting the current Activity.</p>
<p>The search framework manages the life of the search dialog. When users execute a search, the
search framework passes the query text to your application so your application can perform a
search. Figure 1 shows an example of the search dialog with optional search suggestions.</p>
<p>Once your application is set up to use the search dialog, you can:</p>
<ul>
<li>Enable voice search</li>
<li>Provide search suggestions based on recent user queries</li>
<li>Provide custom search suggestions that match actual results in your application data</li>
<li>Offer your application's search suggestions in the system-wide Quick Search Box</li>
</ul>
<p class="note"><strong>Note</strong>: The search framework does <em>not</em> provide APIs to
search your data. To perform a search, you need to use APIs appropriate for your data. For example,
if your data is stored in an SQLite database, you should use the {@link android.database.sqlite}
APIs to perform searches.</p>
<p>The following documents show you how to use the search dialog in your application:</p>
<dl>
<dt><strong><a href="search-dialog.html">Using the Android Search Dialog</a></strong></dt>
<dd>How to set up your application to use the search dialog. </dd>
<dt><strong><a href="adding-recent-query-suggestions.html">Adding Recent Query
Suggestions</a></strong></dt>
<dd>How to show suggestions based on queries previously used in the search dialog.</dd>
<dt><strong><a href="adding-custom-suggestions.html">Adding Custom Suggestions</a></strong></dt>
<dd>How to show suggestions based on custom data from your application and offer your suggestions
in the system-wide Quick Search Box.</dd>
<dt><strong><a href="searchable-config.html">Searchable Configuration</a></strong></dt>
<dd>A reference for the searchable configuration file (though the other
documents also discuss the configuration file in terms of specific behaviors).</dd>
</dl>
<h2>Protecting User Privacy</h2>
<p>When you implement search in your application, take steps to protect the user's
privacy. Many users consider their activities on the phone&mdash;including searches&mdash;to
be private information. To protect each user's privacy, you should abide by the following
principles:</p>
<ul>
<li><strong>Don't send personal information to servers, but if you must, do not log it.</strong>
<p>Personal information is any information that can personally identify your users, such as their
names, email addresses, billing information, or other data that can be reasonably linked to such
information. If your application implements search with the assistance of a server, avoid sending
personal information along with the search queries. For example, if you are searching for businesses
near a zip code,
you don't need to send the user ID as well; send only the zip code to the server. If you must
send the personal information, you should not log it. If you must log it, protect that data
very carefully and erase it as soon as possible.</p>
</li>
<li><strong>Provide the user with a way to clear their search history.</strong>
<p>The search framework helps your application provide context-specific suggestions while the user
types. Sometimes these
suggestions are based on previous searches or other actions taken by the user in an earlier
session. A user might not wish for previous searches to be revealed to other device users, for
instance, if they share their phone with a friend. If your application provides suggestions that can
reveal previous activities, you should implement the ability for the user to clear the search
history. If you are using {@link android.provider.SearchRecentSuggestions}, you can simply call the
{@link android.provider.SearchRecentSuggestions#clearHistory()} method. If you are implementing
custom suggestions, you'll need to provide a similar "clear history" method in your provider that
the user can execute.</p>
</li>
</ul>

View File

@ -0,0 +1,576 @@
page.title=Using the Android Search Dialog
parent.title=Search
parent.link=index.html
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
<ol>
<li><a href="#TheBasics">The Basics</a></li>
<li><a href="#SearchableConfiguration">Creating a Searchable Configuration</a></li>
<li><a href="#SearchableActivity">Creating a Searchable Activity</a>
<ol>
<li><a href="#DeclaringSearchableActivity">Declaring a searchable Activity</a></li>
<li><a href="#PerformingSearch">Performing a search</a></li>
</ol>
</li>
<li><a href="#InvokingTheSearchDialog">Invoking the Search Dialog</a>
<ol>
<li><a href="#LifeCycle">The impact of the search dialog on your Activity life-cycle</a></li>
</ol>
</li>
<li><a href="#SearchContextData">Passing Search Context Data</a></li>
<li><a href="#VoiceSearch">Adding Voice Search</a></li>
</ol>
<h2>Key classes</h2>
<ol>
<li>{@link android.app.SearchManager}</li>
</ol>
<h2>Related samples</h2>
<ol>
<li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable
Dictionary</a></li>
</ol>
<h2>Downloads</h2>
<ol>
<li><a href="{@docRoot}shareables/search_icons.zip">search_icons.zip</a></li>
</ol>
<h2>See also</h2>
<ol>
<li><a href="adding-recent-query-suggestions.html">Adding Recent Query Suggestions</a></li>
<li><a href="adding-custom-suggestions.html">Adding Custom Suggestions</a></li>
<li><a href="searchable-config.html">Searchable Configuration</a></li>
</ol>
</div>
</div>
<p>When you want to implement search in your application, the last thing you should have to worry
about is where to put the search box. When you implement search with the Android search framework,
you don't have to. When the user invokes search, a search dialog appears at the top of the screen
with your application icon to the left of the search box. When the user executes the search, your
application receives the query so it can search your application's data. An example of the search
dialog is shown in figure 1.</p>
<p>This guide shows you how to set up your application to provide search in the search
dialog. When you use the search dialog, you provide a standardized search
experience and can add features such as voice search and search suggestions.</p>
<h2 id="TheBasics">The Basics</h2>
<div class="figure" style="width:250px">
<img src="{@docRoot}images/search/search-ui.png" alt="" height="417" />
<p class="img-caption"><strong>Figure 1.</strong> Screenshot of an application's search dialog.</p>
</div>
<p>The Android search framework manages the search dialog for your application. You never need
to draw it or worry about where it is, and your Activity is not interrupted when the search dialog
appears. The Search Manager ({@link android.app.SearchManager}) is the component that does this work
for you. It manages the life of the search dialog and sends your application the user's search
query.</p>
<p>When the user executes a search, the Search Manager creates an {@link android.content.Intent} to
pass the search query to the Activity that you've declared to handle searches. Basically, all you
need is an Activity that receives the search Intent, performs the search, and presents the results.
Specifically, you need the following:</p>
<dl>
<dt>A searchable configuration</dt>
<dd>An XML file that configures the search dialog and includes settings for features such as voice
search, search suggestion, and the hint text.</dd>
<dt>A searchable Activity</dt>
<dd>The {@link android.app.Activity} that receives the search query, then searches your data and
displays the search results.</dd>
<dt>A mechanism by which the user can invoke search</dt>
<dd>The device search key invokes the search dialog, by default. However, a dedicated search key
is not guaranteed on all devices, so provide another means by which the user can invoke a search,
such as a search button in the Options Menu or elsewhere in the Activity UI.</dd>
</dl>
<h2 id="SearchableConfiguration">Creating a Searchable Configuration</h2>
<p>The searchable configuration is an XML file that defines several settings for the search
dialog in your application. This file is traditionally named {@code searchable.xml} and must be
saved in the {@code res/xml/} project directory.</p>
<p>The file must consist of the {@code &lt;searchable&gt;} element as the root node and specify one
or more attributes that configure your search dialog. For example:</p>
<pre>
&lt;?xml version="1.0" encoding="utf-8"?>
&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_label"
android:hint="@string/search_hint" >
&lt;/searchable>
</pre>
<p>The {@code android:label} attribute is the only required attribute and points to a string
resource, which should be the same as the application name. This label isn't actually visible to the
user until you enable suggestions for Quick Search Box, at which point, this label is visible in the
list of Searchable items in the system Settings.</p>
<p>Though it's not required, we recommend that you always include the {@code android:hint}
attribute, which provides a hint string in the search dialog's text box before the user
enters their query. The hint is important because it provides important clues to users about what
they can search.</p>
<p class="note"><strong>Tip:</strong> For consistency among other
Android applications, you should format the string for {@code android:hint} as "Search
<em>&lt;content-or-product&gt;</em>". For example, "Search songs and artists" or "Search
YouTube".</p>
<p>The {@code &lt;searchable&gt;} element accepts several other attributes. Most attributes apply
only when configuring features such as search suggestions and voice search.</p>
<p>For more details about the searchable configuration file, see the <a
href="{@docRoot}guide/topics/search/searchable-config.html">Searchable Configuration</a>
reference.</p>
<h2 id="SearchableActivity">Creating a Searchable Activity</h2>
<p>When the user executes a search from the search dialog, the Search Manager takes the query
and sends it to your searchable {@link android.app.Activity} in the {@link
android.content.Intent#ACTION_SEARCH} {@link android.content.Intent}. Your searchable Activity
then searches your data using the query and presents the results to the user.</p>
<p>In order for the Search Manager to know where to deliver the search query, you must declare your
searchable Activity in the Android manifest file.</p>
<h3 id="DeclaringSearchableActivity">Declaring a searchable Activity</h3>
<p>If you don't have one already, create an {@link android.app.Activity} that performs
searches and present search results. To set up this Activity as your searchable Activity:</p>
<ol>
<li>Declare the Activity to accept the {@link android.content.Intent#ACTION_SEARCH} {@link
android.content.Intent}, in an <a
href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a>
element.</li>
<li>Apply the searchable configuration, in a <a
href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code &lt;meta-data&gt;}</a>
element.</li>
</ol>
<p>For example:</p>
<pre>
&lt;application ... >
&lt;activity android:name=".MySearchableActivity" >
&lt;intent-filter>
&lt;action android:name="android.intent.action.SEARCH" />
&lt;/intent-filter>
&lt;meta-data android:name="android.app.searchable"
android:resource="@xml/searchable"/>
&lt;/activity>
...
&lt;/application>
</pre>
<p>The {@code &lt;meta-data&gt;} element must include the {@code android:name} attribute with a
value of {@code "android.app.searchable"} and the {@code android:resource} attribute with a
reference to the searchable configuration file (in this example, it
refers to the {@code res/xml/searchable.xml} file).</p>
<p class="note"><strong>Note:</strong> The {@code &lt;intent-filter&gt;} does not need a <a
href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category&gt;}</a> with the
{@code DEFAULT} value, because the Search Manager delivers the {@link
android.content.Intent#ACTION_SEARCH} Intent explicitly to your searchable Activity by name.</p>
<p>The search dialog is not, by default, available from every Activity of your
application. Rather, the search dialog is presented to users only when they
invoke search from a searchable context of your application. A searchable context is any Activity
for which you have
declared searchable meta-data in the manifest file. For example, the searchable Activity itself
(declared in the manifest snippet above) is
a searchable context because it includes meta-data that defines the
searchable configuration. Any other Activity in your application is not a searchable context, by
default, and thus, does not reveal the search dialog. However, you probably do want the search
dialog available from your other activities (and to launch the searchable Activity when the user
executes a search). You can do exactly that.</p>
<p>If you want all of your activities to provide the search dialog, add another {@code
&lt;meta-data&gt;} element inside the {@code
&lt;application&gt;} element. Use this element to declare the existing searchable Activity as the
default searchable Activity. For example:</p>
<pre>
&lt;application ... >
&lt;activity android:name=".MySearchableActivity" >
&lt;intent-filter>
&lt;action android:name="android.intent.action.SEARCH" />
&lt;/intent-filter>
&lt;meta-data android:name="android.app.searchable"
android:resource="@xml/searchable"/>
&lt;/activity>
&lt;activity android:name=".AnotherActivity" ... >
&lt;/activity>
&lt;!-- declare the default searchable Activity for the whole app --&gt;
<b>&lt;meta-data android:name="android.app.default_searchable"
android:value=".MySearchableActivity" /&gt;</b>
...
&lt;/application>
</pre>
<p>The {@code &lt;meta-data&gt;} element with the {@code android:name} attribute value of
{@code "android.app.default_searchable"} specifies a default searchable Activity for the context in
which it is placed (which, in this case, is the entire application). The searchable Activity to
use is specified with the {@code android:value} attribute. All other activities in the
application, such as {@code AnotherActivity}, are now considered a searchable context and can invoke
the search dialog. When a search is executed, {@code MySearchableActivity} is launched to handle
the search query.</p>
<p>You can also control which activities provide search at a more granular level.
To specify only an individual Activity as a searchable context, place the {@code
&lt;meta-data&gt;} with the {@code
"android.app.default_searchable"} name inside the respective {@code &lt;activity&gt;}
element (rather than inside the {@code &lt;application&gt;} element). While uncommon, you
can also create more than one searchable Activity and provide each one in different contexts of your
application, either by declaring a different searchable Activity in each {@code &lt;activity&gt;}
element, or by declaring a default searchable Activity for the entire application and then
overriding it with a {@code &lt;meta-data&gt;} element inside certain activities. (You might do
this if you want to search different sets of data that cannot be handled by the same
searchable Activity, depending on the currently open Activity.)</p>
<h3 id="PerformingSearch">Performing a search</h3>
<p>Once you have declared your searchable Activity, performing a search for the user involves
three steps:</p>
<ol>
<li><a href="#ReceivingTheQuery">Receiving the query</a></li>
<li><a href="#SearchingYourData">Searching your data</a></li>
<li><a href="#PresentingTheResults">Presenting the results</a></li>
</ol>
<p>Traditionally, your search results should be presented in a {@link android.widget.ListView}, so
you might want your searchable Activity to extend {@link android.app.ListActivity}, which
provides easy access to {@link android.widget.ListView} APIs. (See the <a
href="{@docRoot}resources/tutorials/views/hello-listview.html">List View Tutorial</a> for a simple
{@link android.app.ListActivity} sample.)</p>
<h4 id="ReceivingTheQuery">Receiving the query</h4>
<p>When a user executes a search from the search dialog, the Search Manager sends the {@link
android.content.Intent#ACTION_SEARCH} {@link android.content.Intent} to your searchable Activity.
This Intent carries the search query in the
{@link android.app.SearchManager#QUERY QUERY} string extra. You must check for
this Intent when the Activity starts and extract the string. For example, here's how you can get the
query when your Activity starts:</p>
<pre>
&#64;Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search);
Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
doMySearch(query);
}
}
</pre>
<p>The {@link android.app.SearchManager#QUERY QUERY} string is always included with
the {@link android.content.Intent#ACTION_SEARCH} Intent. In this example, the query is
retrieved and passed to a local {@code doMySearch()} method where the actual search operation
is done.</p>
<h4 id="SearchingYourData">Searching your data</h4>
<p>The process of storing and searching your data is unique to your application.
You can store and search your data in many ways, but this guide does not show you how to store your
data and search it. Storing and searching your data is something you should carefully consider in
terms of your needs and your data. However, here are some tips you might be able to apply:</p>
<ul>
<li>If your data is stored in a SQLite database on the device, performing a full-text search
(using FTS3, rather than a LIKE query) can provide a more robust search across text data and can
produce results significantly faster. See <a href="http://sqlite.org/fts3.html">sqlite.org</a>
for information about FTS3 and the {@link android.database.sqlite.SQLiteDatabase} class for
information about SQLite on Android. Also look at the <a
href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable Dictionary</a> sample
application to see a complete SQLite implementation that performs searches with FTS3.</li>
<li>If your data is stored online, then the perceived search performance might be
inhibited by the user's data connection. You might want to display a spinning progress wheel until
your search returns. See {@link android.net} for a reference of network APIs and <a
href="{@docRoot}guide/topics/ui/dialogs.html#ProgressDialog">Creating a Progress Dialog</a> to see
how you can display a progress wheel.</li>
</ul>
<div class="sidebox-wrapper">
<div class="sidebox">
<h2>About Adapters</h2>
<p>An Adapter binds individual items from a set of data into individual {@link
android.view.View} objects. When the Adapter
is applied to a {@link android.widget.ListView}, the Views are injected as individual items of the
list. {@link
android.widget.Adapter} is simply an interface, so implementations such as {@link
android.widget.CursorAdapter} (for binding data from a {@link android.database.Cursor}) are needed.
If none of the existing implementations work for your data, then you should implement your own from
{@link android.widget.BaseAdapter}. Install the SDK Samples package for API Level 4 to see the
original version of the Searchable Dictionary, which creates a custom BaseAdapter.</p>
</div>
</div>
<p>Regardless of where your data lives and how you search it, we recommend that you return search
results to your searchable Activity with an {@link android.widget.Adapter}. This way, you can easily
present all the search results in a {@link android.widget.ListView}. If your data comes from a
SQLite database query, then you can apply your results to a {@link android.widget.ListView}
using a {@link android.widget.CursorAdapter}. If your data comes in some other type of format, then
you can create an extension of the {@link android.widget.BaseAdapter}.</p>
<h4 id="PresentingTheResults">Presenting the results</h4>
<p>Presenting your search results is mostly a UI detail that is not handled by the search APIs.
However, one option is to create your searchable Activity to extend {@link
android.app.ListActivity} and call {@link
android.app.ListActivity#setListAdapter(ListAdapter)}, passing it an {@link
android.widget.Adapter} that is bound to your data. This injects all the
results into the Activity {@link android.widget.ListView}.</p>
<p>For more help presenting your results, see the {@link android.app.ListActivity}
documentation.</p>
<p>Also see the <a
href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable Dictionary</a> sample
for an a complete demonstration of how to search an SQLite database and use an
{@link android.widget.Adapter} to provide results in a {@link android.widget.ListView}.</p>
<h2 id="InvokingTheSearchDialog">Invoking the Search Dialog</h2>
<p>Once you have a searchable Activity, invoking the search dialog is easy. Many Android
devices provide a dedicated SEARCH key, which reveals the search dialog when the user presses it
from a searchable context of your application. However, you should not assume that a SEARCH
key is available on the user's device and should always provide a search button in your UI that
invokes search.</p>
<p>To invoke search from your Activity, call {@link android.app.Activity#onSearchRequested()}.</p>
<p>For instance, you should provide a menu item in your <a
href="{@docRoot}guide/topics/ui/menus.html#options-menu">Options Menu</a> or a button in your UI to
invoke search with this method. The <a
href="{@docRoot}shareables/search_icons.zip">search_icons.zip</a> file includes icons for
medium and high density screens, which you can use for your search menu item or button (low density
screens automatically scale-down the hdpi image by one half). </p>
<!-- ... maybe this should go into the Creating Menus document ....
<p>If you chose to provide a shortcut key for the menu item, using {@link
android.view.MenuItem#setAlphabeticShortcut(char)}, then SearchManager.MENU_KEY is the recommended
key character, representing the default search key.</p>
-->
<p>You can also enable "type-to-search" functionality, which reveals the search dialog when the
user starts typing on the keyboard and the keystrokes are inserted into the search dialog. You can
enable type-to-search in your Activity by calling
{@link android.app.Activity#setDefaultKeyMode(int) setDefaultKeyMode}({@link
android.app.Activity#DEFAULT_KEYS_SEARCH_LOCAL}) during your Activity's
{@link android.app.Activity#onCreate(Bundle) onCreate()} method.</p>
<h3 id="LifeCycle">The impact of the search dialog on your Activity lifecycle</h3>
<p>The search dialog is a {@link android.app.Dialog} that floats at the top of the
screen. It does not cause any change in the Activity stack, so when the search dialog appears, no
lifecycle methods for the currently open Activity (such as {@link
android.app.Activity#onPause()}) are called. Your Activity just loses input focus as it is given to
the search dialog.
</p>
<p>If you want to be notified when search is invoked, override the {@link
android.app.Activity#onSearchRequested()} method. When the system calls this method, you can do any
work you want to when your Activity looses input focus to the search dialog (such as pause
animations). Unless you are <a href="#SearchContextData">passing search context data</a>
(discussed below), you should end the method by calling the super class implementation. For
example:</p>
<pre>
&#64;Override
public boolean onSearchRequested() {
pauseSomeStuff();
return super.onSearchRequested();
}
</pre>
<p>If the user cancels search by pressing the BACK key, the Activity in which search was
invoked re-gains input focus. You can register to be notified when the search dialog is
closed with {@link android.app.SearchManager#setOnDismissListener(SearchManager.OnDismissListener)
setOnDismissListener()}
and/or {@link android.app.SearchManager#setOnCancelListener(SearchManager.OnCancelListener)
setOnCancelListener()}. You
should need to register only the {@link android.app.SearchManager.OnDismissListener
OnDismissListener}, because it is called every time the search dialog closes. The {@link
android.app.SearchManager.OnCancelListener OnCancelListener} only pertains to events in which the
user explicitly exited the search dialog, so it is not called when a search is executed (in which
case, the search dialog naturally disappears).</p>
<p>If the current Activity is not the searchable Activity, then the normal Activity lifecycle
events are triggered once the user executes a search (the current Activity receives {@link
android.app.Activity#onPause()} and so forth, as
described in <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">Application
Fundamentals</a>). If, however, the current Activity is the searchable Activity, then one of two
things happens:</p>
<ol type="a">
<li>By default, the searchable Activity receives the {@link
android.content.Intent#ACTION_SEARCH} Intent with a call to {@link
android.app.Activity#onCreate(Bundle) onCreate()} and a new instance of the
Activity is brought to the top of the Activity stack. There are now two instances of your
searchable Activity in the Activity stack (so pressing the BACK key goes back to the previous
instance of the searchable Activity, rather than exiting the searchable Activity).</li>
<li>If you set {@code android:launchMode} to "singleTop", then the
searchable Activity receives the {@link android.content.Intent#ACTION_SEARCH} Intent with a call
to {@link android.app.Activity#onNewIntent(Intent)}, passing the new {@link
android.content.Intent#ACTION_SEARCH} Intent here. For example, here's how you might handle
this case, in which the searchable Activity's launch mode is "singleTop":
<pre>
&#64;Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search);
handleIntent(getIntent());
}
&#64;Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
doMySearch(query);
}
}
</pre>
<p>Compared to the example code in the section about <a href="#PerformingSearch">Performing a
Search</a>, all the code to handle the
search Intent is now in the {@code handleIntent()} method, so that both {@link
android.app.Activity#onCreate(Bundle)
onCreate()} and {@link android.app.Activity#onNewIntent(Intent) onNewIntent()} can execute it.</p>
<p>When the system calls {@link android.app.Activity#onNewIntent(Intent)}, the Activity has
not been restarted, so the {@link android.app.Activity#getIntent()} method
returns the same Intent that was received with {@link
android.app.Activity#onCreate(Bundle) onCreate()}. This is why you should call {@link
android.app.Activity#setIntent(Intent)} inside {@link
android.app.Activity#onNewIntent(Intent)} (so that the Intent saved by the Activity is updated in
case you call {@link android.app.Activity#getIntent()} in the future).</p>
</li>
</ol>
<p>The second scenario using "singleTop" launch mode is usually ideal, because chances are good that
once a search is done, the user will perform additional searches and it's a bad experience if your
application creates multiple instances of the searchable Activity. So, we recommend that you set
your searchable Activity to "singleTop" launch mode in the application
manifest. For example:</p>
<pre>
&lt;activity android:name=".MySearchableActivity"
<b>android:launchMode="singleTop"</b> >
&lt;intent-filter>
&lt;action android:name="android.intent.action.SEARCH" />
&lt;/intent-filter>
&lt;meta-data android:name="android.app.searchable"
android:resource="@xml/searchable"/>
&lt;/activity>
</pre>
<h2 id="SearchContextData">Passing Search Context Data</h2>
<p>To refine your search criteria from the current Activity instead of depending only on the user's
search query, you can provide additional data in the Intent that the Search Manager sends to your
searchable Activity. In a simple case, you can make your refinements inside the searchable
Activity, for every search made, but if your
search criteria varies from one searchable context to another, then you can pass whatever data
is necessary to refine your search in the {@link android.app.SearchManager#APP_DATA} {@link
android.os.Bundle}, which is included in the {@link android.content.Intent#ACTION_SEARCH}
Intent.</p>
<p>To pass this kind of data to your searchable Activity, override {@link
android.app.Activity#onSearchRequested()} method for the Activity in which search can be invoked.
For example:</p>
<pre>
&#64;Override
public boolean onSearchRequested() {
Bundle appData = new Bundle();
appData.putBoolean(MySearchableActivity.JARGON, true);
startSearch(null, false, appData, false);
return true;
}
</pre>
<p>Returning "true" indicates that you have successfully handled this callback event. Then in your
searchable Activity, you can extract the data placed inside {@code appdata} from the {@link
android.app.SearchManager#APP_DATA} {@link android.os.Bundle} to refine the search. For example:</p>
<pre>
Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);
if (appData != null) {
boolean jargon = appData.getBoolean(MySearchableActivity.JARGON);
}
</pre>
<p class="caution"><strong>Caution:</strong> Never call the {@link
android.app.Activity#startSearch(String,boolean,Bundle,boolean) startSearch()} method from outside
the {@link android.app.Activity#onSearchRequested()} callback method. To invoke the search dialog
in your Activity, always call {@link android.app.Activity#onSearchRequested()}. Otherwise, {@link
android.app.Activity#onSearchRequested()} is not called and customizations (such as the addition of
{@code appData} in the above example) are missed.</p>
<h2 id="VoiceSearch">Adding Voice Search</h2>
<p>You can add voice search functionality to your search dialog by adding the {@code
android:voiceSearchMode} attribute to your searchable configuration. This adds a voice search
button in the search dialog that launches a voice prompt. When the user
has finished speaking, the transcribed search query is sent to your searchable
Activity.</p>
<p>For example:</p>
<pre>
&lt;?xml version="1.0" encoding="utf-8"?>
&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search_label"
android:hint="@string/search_hint"
<b>android:voiceSearchMode="showVoiceSearchButton|launchRecognizer"</b> >
&lt;/searchable>
</pre>
<p>The value {@code showVoiceSearchButton} is required to enable voice
search, while the second value, {@code launchRecognizer}, specifies that the voice search button
should launch a recognizer that returns the transcribed text to the searchable Activity.</p>
<p>You can provide additional attributes to specify the voice search behavior, such
as the language to be expected and the maximum number of results to return. See the <a
href="searchable-config.html">Searchable Configuration</a> reference for more information about the
available attributes.</p>
<p class="note"><strong>Note:</strong> Carefully consider whether voice search is appropriate for
your application. All searches performed with the voice search button are immediately sent to
your searchable Activity without a chance for the user to review the transcribed query. Sufficiently
test the voice recognition and ensure that it understands the types of queries that
the user might submit inside your application.</p>

View File

@ -0,0 +1,381 @@
page.title=Searchable Configuration
parent.title=Search
parent.link=index.html
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>See also</h2>
<ol>
<li><a href="search-dialog.html">Using the Android Search Dialog</a></li>
<li><a href="adding-recent-query-suggestions.html">Adding Recent Query Suggestions</a></li>
<li><a href="adding-custom-suggestions.html">Adding Custom Suggestions</a></li>
</ol>
</div>
</div>
<p>To utilize the Android search framework and provide a custom search dialog, your
application must provide a search
configuration in the form of an XML resource. This document describes the search configuration XML
in terms of its syntax and usage. For more information about how to implement search
features for your application, see the developer guide about <a
href="index.html">Search</a>.</p>
<dl class="xml">
<dt>file location:</dt>
<dd><code>res/xml/<em>filename</em>.xml</code><br/>
Android uses the filename as the resource ID.</dd>
<dt>syntax:</dt>
<dd>
<pre class="stx">
&lt;?xml version="1.0" encoding="utf-8"?>
&lt;<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>"
&gt;
&lt;<a href="#actionkey-element">actionkey</a>
android:keycode="<em>{@link android.view.KeyEvent KEYCODE}</em>"
android:queryActionMsg="<em>string</em>"
android:suggestActionMsg="<em>string</em>"
android:suggestActionMsgColumn="<em>string</em>" &gt;
&lt;/searchable&gt;
</pre>
</dd>
<dt>elements:</dt>
<dd>
<dl class="tag-list">
<dt id="searchable-element"><code>&lt;searchable&gt;</code></dt>
<dd>Defines all search configurations used with the search dialog.
<p class="caps">attributes:</p>
<dl class="atn-list">
<dt><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 &lt;activity&gt;}</a> or
<a href="{@docRoot}guide/topics/manifest/application-element.html#label">{@code
&lt;application&gt;}</a> manifest element. This label is only visible to the user when you set
<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>
<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>&lt;content-or-product&gt;</em>". For example,
"Search songs and artists" or "Search YouTube".</dd>
<dt><code>android:searchMode</code></dt>
<dd><em>Keyword</em>. Sets additional modes that control the search dialog presentation.
Currently available modes define how the query text that appears in the search dialog
should be rewritten when a custom suggestion receives focus. The following mode values are accepted:
<table>
<tr><th>Value</th><th>Description</th></tr>
<tr>
<td><code>"queryRewriteFromText"</code></td>
<td>Use the value from the {@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}
colum to rewrite the query text in the search dialog.</td>
</tr>
<tr>
<td><code>"queryRewriteFromData"</code></td>
<td>Use the value from the
{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column to rewrite the
query text in the search dialog. This should only be used when the values in
{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} are suitable for user
inspection and editing, typically HTTP URI's.</td>
</tr>
</table>
<p>For more information, see the discussion about rewriting the query text in <a
href="adding-custom-suggestions.html#RewritingQueryText">Adding Custom Suggestions</a>.</p>
</dd>
<dt><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>
<dd><em>Keyword</em>. Defines the type of input method (such as the type of soft keyboard)
to use with the search dialog. 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>
<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
return in the soft keyboard). See {@link android.R.attr#imeOptions} for a list of suitable values
for this attribute.
</dd>
</dl>
<h4>Search suggestion attributes</h4>
<p>If you have defined a content provider to generate search suggestions, you need to
define additional attributes that configure communications with the content
provider. When providing search suggestions, you need some of the following
{@code &lt;searchable>} attributes:</p><br/>
<dl class="atn-list">
<dt><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 &lt;provider>} element.</dd>
<dt><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.
This is only required if you have a single content provider issuing different types
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>
<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
actual query string that has been typed by the user (for example, {@code "query=?"}). However, you
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>
<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>
<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
a suggestion.</dd>
<dt><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 Search Manager will not query your
content provider for anything shorter than the threshold. The default value is 0.</dd>
</dl>
<p>For more information about the above attributes for search suggestions, see the guides for
<a href="adding-recent-query-suggestions.html">Adding Recent Query Suggestions</a> and
<a href="adding-custom-suggestions.html">Adding Custom Suggestions</a>.</p>
<h4>Quick Search Box attributes</h4>
<p>To make your custom search suggestions available to Quick Search Box, you need some of the
following {@code &lt;searchable>} attributes:</p><br/>
<dl class="atn-list">
<dt><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>
<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>
<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
"false", supersets are ignored for a single session ("bob" does not invoke a requery). This lasts
only for the life of the search dialog (when the search dialog is reopened, "bo" queries your
content provider again). The default value is false.</dd>
</dl>
<h4>Voice search attributes</h4>
<p>To enable voice search for your search dialog, you'll need some of the
following {@code &lt;searchable>} attributes:</p><br/>
<dl class="atn-list">
<dt><code>android:voiceSearchMode</code></dt>
<dd><em>Keyword</em>. (Required to provide voice search capabilities.)
Enables voice search for the search dialog, with a specific mode for voice search.
(Voice search may not be provided by the device, in which case these flags
have no effect.) The following mode values are accepted:
<table>
<tr><th>Value</th><th>Description</th></tr>
<tr>
<td><code>"showVoiceSearchButton"</code></td>
<td>Display a voice search button, if voice search is available on the device. If set,
then either {@code "launchWebSearch"} or {@code "launchRecognizer"} must also be set
(separated by the pipe | character).</td>
</tr>
<tr>
<td><code>"launchWebSearch"</code></td>
<td>The voice search button takes the user directly
to a built-in voice web search activity. Most applications don't need this flag, as
it takes the user away from the Activity in which search was invoked.</td>
</tr>
<tr>
<td><code>"launchRecognizer"</code></td>
<td>The voice search button takes
the user directly to a built-in voice recording activity. This Activity
prompts the user to speak, transcribes the spoken text, and forwards the resulting
query text to the searchable Activity, just as if the user typed it into the
search UI and clicked the search button.</td>
</tr>
</table>
</dd>
<dt><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>
<tr><th>Value</th><th>Description</th></tr>
<tr>
<td><code>"free_form"</code></td>
<td>Use free-form speech recognition for dictating queries. This is primarily
optimized for English. This is the default.</td>
</tr>
<tr>
<td><code>"web_search"</code></td>
<td>Use web-search-term recognition for shorter, search-like phrases. This is
available in more languages than "free_form".</td>
</tr>
</table>
<p>Also see
{@link android.speech.RecognizerIntent#EXTRA_LANGUAGE_MODEL} for more
information.</p></dd>
<dt><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>
<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>
<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
query. Must be 1 or greater. Use {@link android.speech.RecognizerIntent#EXTRA_RESULTS} to
get the results from the Intent.
If not provided, the recognizer chooses how many results to return.</dd>
</dl>
</dd> <!-- end searchable element -->
<dt id="actionkey-element"><code>&lt;actionkey&gt;</code></dt>
<dd>Defines a device key and behavior for a search action. A search action provides a
special behavior at the touch of a button on the device, based on the current query or focused
suggestion. For example, the Contacts application provides a search action to initiate a phone call
to the currenly focused contact suggestion at the press of the CALL button.
<p>Not all action keys are available on every device, and not
all keys are allowed to be overriden in this way. For example, the "Home" key cannot be used and
must always return to the home screen. Also be sure not to define an action
key for a key that's needed for typing a search query. This essentially limits the
available and reasonable action keys to the call button and menu button. Also note that action
keys are not generally discoverable, so you should not provide them as a core user feature.</p>
<p>You must define the <code>android:keycode</code> to define the key and at least one of the
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>
<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
{@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} Intent that is passed to your
searchable Activity. To examine the key code, use
{@link android.content.Intent#getIntExtra getIntExtra(SearchManager.ACTION_KEY)}. Not all
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>
<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 Search Manager
passes to your searchable Activity. To examine the string, use
{@link android.content.Intent#getStringExtra
getStringExtra(SearchManager.ACTION_MSG)}.</dd>
<dt><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 Search Manager passes to your searchable Activity (using the action
you've defined for the suggestion). To examine the string,
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>
<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
action key on a suggestion-by-suggestion basis, because, instead of using the {@code
android:suggestActionMsg} attribute to define the action message for all suggestions, each entry in
your content provider provides its own action message.
<p>First, you must define a column in your
content provider for each suggestion to provide an action message, then provide the name of that
column in this attribute. The Search Manager looks at your suggestion cursor,
using the string provided here to select your action message column, and
then select the action message string from the Cursor. That string is added to the
Intent that the Search Manager passes to your searchable Activity (using the action you've
defined for suggestions). To examine the string, use {@link
android.content.Intent#getStringExtra getStringExtra(SearchManager.ACTION_MSG)}. If the data
does not exist for the selected suggestion, the action key is ignored.</dd>
</dl>
</dd><!-- end action key -->
</dl>
</dd><!-- end elements -->
<dt>example:</dt>
<dd>XML file saved at <code>res/xml/searchable.xml</code>:
<pre>
&lt;?xml version="1.0" encoding="utf-8"?>
&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search_label"
android:hint="@string/search_hint"
android:searchSuggestAuthority="dictionary"
android:searchSuggestIntentAction="android.intent.action.VIEW"
android:includeInGlobalSearch="true"
android:searchSettingsDescription="@string/settings_description" >
&lt;/searchable>
</pre>
</dd> <!-- end example -->
</dl>