Merge "docs: add Search dev guide new docs: Search (topic home page) Using the Android Search Box Adding Recent Query Suggestions Adding Custom Suggestions Searchable Configuration"

This commit is contained in:
Scott Main
2010-03-17 11:43:01 -07:00
committed by Android (Google) Code Review
10 changed files with 1946 additions and 1 deletions

View File

@@ -143,6 +143,7 @@
<li><a href="<?cs var:toroot ?>guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/path-permission-element.html">&lt;path-permission&gt;</a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></li>
@@ -198,7 +199,18 @@
</a></li>
<li><a href="<?cs var:toroot?>guide/topics/wireless/bluetooth.html">
<span class="en">Bluetooth</span>
</a> <span class="new">new!</span></li>
</a></li>
<li class="toggle-list">
<div><a href="<?cs var:toroot?>guide/topics/search/index.html">
<span class="en">Search</span>
</a> <span class="new">new!</span></div>
<ul>
<li><a href="<?cs var:toroot?>guide/topics/search/search-dialog.html">Using the Android Search Dialog</a></li>
<li><a href="<?cs var:toroot?>guide/topics/search/adding-recent-query-suggestions.html">Adding Recent Query Suggestions</a></li>
<li><a href="<?cs var:toroot?>guide/topics/search/adding-custom-suggestions.html">Adding Custom Suggestions</a></li>
<li><a href="<?cs var:toroot?>guide/topics/search/searchable-config.html">Searchable Configuration</a></li>
</ul>
</li>
</ul>
</li>

View File

@@ -0,0 +1,699 @@
page.title=Adding Custom Suggestions
parent.title=Search
parent.link=index.html
@jd:body
<div id="qv-wrapper">
<div id="qv">
<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>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>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>
<li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable
Dictionary sample app</a></li>
</ol>
</div>
</div>
<p>The Android search framework provides the ability for your application to
provide suggestions while the user types into the Android search dialog. In this guide, you'll learn
how to create custom suggestions. These are suggestions based on custom data provided by 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. Once you provide
custom suggestions, you then make them available to the system-wide Quick Search Box, providing
access to your content from outside your application.</p>
<p>Before you begin, you need to have implemented the Android search dialog for searches in your
application. If you haven't done this, see <a href="search-dialog.html">Using the Android Search
Dialog</a>.</p>
<h2 id="TheBasics">The Basics</h2>
<img src="{@docRoot}images/search/search-suggest-custom.png" alt="" height="417"
style="float:right;clear:right;" />
<p>When the user selects a custom suggestions, the Search Manager will send a customized Intent to
your searchable Activity. Whereas a normal search query will send 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 action), and also include additional 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, you need to 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>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>
<li>Modify the searchable configuration with information about the content provider.</li>
</ul>
<p>Just like the Search Manager handles the rendering of the search dialog, it will also do the work
to display all search suggestions below the search dialog. All you need to do is provide a source
from which the suggestions can be retrieved.</p>
<p class="note"><strong>Note:</strong> If you're not familiar with creating Content
Providers, please 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 also provides search
suggestions, the following procedure will take place as soon as the user types into the Android
search box:</p>
<ul>
<li>The Search Manager takes the search query text (whatever has been typed so far) and performs a
query to the content provider that manages your suggestions.</li>
<li>Your content provider then returns a {@link android.database.Cursor} that points to all
suggestions that are relevant to the search query text.</li>
<li>The Search Manager then displays the list of suggestions provided by the Cursor (as
demonstrated in the screenshot to the right).</li>
</ul>
<p>At this point, the following may 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"?>
&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_label"
android:hint="@string/search_hint"
android:searchSuggestAuthority="my.package.MyCustomSuggestionProvider" >
&lt;/searchable>
</pre>
<p>You may require 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 relevant sections below.</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.</p>
<p>When the user starts typing into the search dialog, the Search Manager will query 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 determine to be good suggestions.</p>
<p>The following two sections describe how the Search Manager will send requests to your Content
Provider and how you can handle them, and define the columns that the Search Manager understands and
expects to be provided in the {@link android.database.Cursor} returned with each query.</p>
<h3 id="HandlingSuggestionQuery">Handling the suggestion query</h3>
<p>When the Search Manager makes a request for suggestions from your content provider, it will call
{@link android.content.ContentProvider#query(Uri,String[],String,String[],String)}. You must
implement this method in your content provider so that it will search your suggestions and return a
Cursor that contains the suggestions you deem relevant.</p>
<p>Here's a summary of the parameters that the Search Manager will pass 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>This will always be 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 will be encoded using URI encoding rules, so you may need to decode
it.</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>Note that {@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>This is always null</dd>
<dt><code>selection</code></dt>
<dd>This is 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 this below.</dd>
<dt><code>selectionArgs</code></dt>
<dd>This 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 this below.</dd>
<dt><code>sortOrder</code></dt>
<dd>This is always null</dd>
</dl>
<p>As you may have realized, there are two ways by which the Search Manager can send you the search
query text. The default manner is for the query text to be included as the last path of the content
URI that is 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 will instead be passed as the first
element of the {@code selectionArgs} string array. Both options are summarized below.</p>
<h4>Get the query in the Uri</h4>
<p>By default, the query will be 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 will return the last segment of the Uri, which is the query text entered in the search
dialog.</p>
<h4>Get the query in the selection arguments</h4>
<p>Instead of using the URI, you may 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 values. In this case, you can
add the {@code android:searchSuggestSelection} attribute to your searchable configuration with your
SQLite selection string. In this selection string, you can include a question mark ("?") as
a placeholder for the actual search query. This selection string will be delivered as the
{@code selection} string parameter, and the query entered into the search dialog will be delivered
as the first element in the {@code selectionArgs} string array parameter.</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"?>
&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_label"
android:hint="@string/search_hint"
android:searchSuggestAuthority="my.package.MyCustomSuggestionProvider"
android:searchSuggestIntentAction="android.Intent.action.VIEW"
android:searchSuggestSelection="word MATCH ?">
&lt;/searchable>
</pre>
<p>When you then receive the {@code selection} and {@code selectionArgs} parameters in your {@link
android.content.ContentProvider#query(Uri,String[],String,String[],String) ContentProvider.query()}
method, they will carry the selection ("word MATCH ?") and the query text, respectively. When
these are passed to an SQLite {@link
android.database.sqlite.SQLiteDatabase#query(String,String[],String,String[],String,String,
String) query} method, they will be synthesized together (replacing the question mark with the query
text, wrapped in single-quotes). Note that if you chose this method and need to add any wildcards to
your query text, you must do so by appending (and/or prefixing) them to the {@code selectionArgs}
parameter, because this is the value that will be wrapped in quotes and inserted in place of the
question mark.</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 will trigger 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 on the fly</h2>
<p>If your search suggestions are not stored in a table format 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 the fly. 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 there to be 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}. There are several columns that the Search
Manager will understand, but only two are required:</p>
<dl>
<dt>{@link android.provider.BaseColumns#_ID}</dt>
<dd>This is the unique row ID for each suggestion. The search dialog requires this in order
to present the suggestions in a ListView.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}</dt>
<dd>This is the line of text that will be presented to the user as a suggestion.</dd>
</dl>
<p>The following columns are all optional (and most will be discussed further in the following
sections, so you may want to skip this list for now):</p>
<dl>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_2}</dt>
<dd>If your Cursor includes this column, then all suggestions will be provided in a two-line
format. The data in this column will be 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>If your Cursor includes this column, then all suggestions will be provided in an
icon-plus-text format with the icon on the left side. This value should be a reference to the
icon. It can be null or zero to indicate no icon in this row.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_ICON_2}</dt>
<dd>If your Cursor includes this column, then all suggestions will be provided in an
icon-plus-text format with the icon on the right side. This value should be a reference to the
icon. It can be null or zero to indicate no icon in this row.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION}</dt>
<dd>If this column exists and this element exists at the given row, this is the action that will
be used when forming the suggestion's Intent . If the element is not provided, the action will be
taken from the {@code android:searchSuggestIntentAction} field in your searchable configuration. At
least one of these
must be present for the suggestion to generate an Intent. Note: 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 from the Cursor .</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA}</dt>
<dd>If this column exists and this element exists at the given row, this is the data that will be
used when forming the suggestion's Intent. If the element is not provided, the data will be taken
from the {@code android:searchSuggestIntentData} field in your searchable configuration. If neither
source is provided,
the Intent's data field will be null. Note: 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 from the Cursor .
</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID}</dt>
<dd>If this column exists and this element exists at the given row, then "/" and this value will
be 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>If this column exists and this element exists at a given row, this is the <em>extra</em> data
that will be used when forming the suggestion's Intent. If not provided, the Intent's extra data
field will be
null. This column allows suggestions to provide additional arbitrary data which will be
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 will be
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 is used to indicate
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 will be stored as a shortcut and never
refreshed. If set to {@link android.app.SearchManager#SUGGEST_NEVER_MAKE_SHORTCUT}, the result will
not be stored as a shortcut.
Otherwise, the shortcut id will be used to check back for 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 is used to specify 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>Again, most of these columns will be discussed in the relevant sections below, so don't worry if
they don't make sense to you now.</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 (instead of performing a search), the Search Manager will send
a custom {@link android.content.Intent} to your searchable Activity. You must define both the
<em>action</em> and <em>data</em> 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 whatever you want and can even be different for each
suggestion.</p>
<p>To declare an Intent action that will be the same for all suggestions, define the action in
the {@code android:searchSuggestIntentAction} attribute of 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"
android:searchSuggestAuthority="my.package.MySuggestionProvider"
android:searchSuggestIntentAction="android.Intent.action.VIEW" >
&lt;/searchable>
</pre>
<p>If you want to declare an Intent action that's unique for each suggestion, 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>
<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 will be 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 will receive 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 suggestions was selected. Specifically,
the data should be something unique for each suggestion, such as the row ID for the suggestion in
your suggestions 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>There are two ways to define the data that is included with the Intent:</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.</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.</li>
</ol>
<p>The first option is straight-forward. Simply 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 will be attached to the Intent exactly as it
is found 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} is used to
create a projection map of column names to aliases.</p>
<p>The second option is to fragment your data URI into the common piece and the unique piece.
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="my.package.MySuggestionProvider"
android:searchSuggestIntentAction="android.Intent.action.VIEW"
android:searchSuggestIntentData="content://my.package/datatable" >
&lt;/searchable>
</pre>
<p>Now 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 will take
the string from {@code android:searchSuggestIntentData}, append a slash ("/") and then add 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>
<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 will be 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 formatted Intents, you
need your searchable Activity to handle these Intents as they are delivered once the user selects a
suggestion. (This is, of course, in addition to handling the {@link
android.content.Intent#ACTION_SEARCH} Intent, which your searchable Activity already does.)
Accepting the new Intent is rather self-explanatory, so we'll skip straight to an example:</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 my suggestions all use ACTION_VIEW)
Uri data = intent.getData());
showResult(rowId);
}
</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 a local
method that will query the content provider for the item specified by the URI and show it.</p>
<h2 id="RewritingQueryText">Rewriting the query text</h2>
<p>If the user navigates through the suggestions list using the device directional controls, 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 currently selected suggestion. 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 will be 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 will be used to rewrite the
query text. Note that 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 will be 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 your application is configured 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 will be required is if your content provider for
custom suggestions requires a permission for read access. In which case, you need to add a special
{@code &lt;path-permission>} 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="my.package.authority"
android:readPermission="com.example.provider.READ_MY_DATA"
android:writePermission="com.example.provider.WRITE_MY_DATA">
&lt;path-permission android:pathPrefix="/search_suggest_query"
android:readPermission="android.permission.GLOBAL_SEARCH" />
&lt;/provider>
</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>Content providers that enforce no permissions are already available to the search
infrastructure.</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="my.package.MySuggestionProvider"
android:searchSuggestIntentAction="android.Intent.action.VIEW"
android:includeInGlobalSearch="true"
android:searchSettingsDescription="@string/search_description" >
&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 will be provided. This attribute should always be included
when {@code android:includeInGlobalSearch} is "true".</p>
<p>Remember that the user must visit this settings menu to enable search suggestions for your
application before your search suggestions will appear in Quick Search Box. As such, if search is an
important aspect of your application, then you may want to consider a way to message this to your
users &mdash; perhaps with a note the first time they launch the app about 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 may 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 may change 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 the following ways:</p>
<ol type="a">
<li>Have Quick Search Box re-query your content provider for a fresh version of the shortcutted
suggestion.
<p>Provide a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} column
and the suggestion will be
re-queried for a fresh version of the suggestion each time the shortcut is displayed. The shortcut
will be quickly displayed with whatever data was most recently available until the refresh query
returns, after which the suggestion will be dynamically refreshed with the new information. The
refresh query will be 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}). The 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 will disappear and the shortcut will be removed).</p>
<p>If a suggestion refers to data that could take longer to refresh, such as a network based
refresh, you may 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" will 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 will never be copied into a shortcut. This should only be necessary if you
absolutely do not want the previously copied suggestion to appear at all. (Recall that if you
provide a normal value for the column then the suggestion shortcut will appear only until the
refresh query returns.)</p></li>
<li>Allow the default shortcut behavior to apply.
<p>Simply 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>Of course, if none of your suggestions will 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 will ultimately decide whether to shortcut
your app's suggestions, considering these values as a strong request from your application.</p>
<h3 id="AboutRanking">About Quick Search Box suggestion ranking</h3>
<p>Once your application's search results are made available to Quick Search Box, how they surface
to the user for a particular query will be determined as appropriate by Quick Search Box ranking.
This may depend on how many other apps have results for that query, and how often the user has
selected on your results compared to those of the other apps. There is no guarantee about how
ranking will occur, or whether your app's suggestions will show at all for a given query. In
general, you can expect that providing quality results will increase the likelihood that your app's
suggestions are provided in a prominent position, and apps that provide lower quality suggestions
will be more likely to be ranked lower and/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,225 @@
page.title=Adding Recent Query Suggestions
parent.title=Search
parent.link=index.html
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>Key classes</h2>
<ol>
<li>{@link android.provider.SearchRecentSuggestions}</li>
<li>{@link android.content.SearchRecentSuggestionsProvider}</li>
</ol>
<h2>In this document</h2>
<ol>
<li><a href="#TheBasics">The Basics</a></li>
<li><a href="#RecentQuerySearchableConfiguration">Modifying the searchable
configuration</a></li>
<li><a href="#RecentQueryContentProvider">Creating a Content Provider</a></li>
<li><a href="#SavingQueries">Saving queries</a></li>
<li><a href="#ClearingSuggestionData">Clearing the suggestion data</a></li>
</ol>
<h2>See also</h2>
<ol>
<li><a href="searchable-config.html">Searchable Configuration</a></li>
</ol>
</div>
</div>
<p>The Android search framework provides the ability for your application to
provide suggestions while the user types into the Android search dialog. In this guide, you'll learn
how to create recent query suggestions. These are suggestions based
on queries previously entered by the user. So, if the user previously searched for "puppies" then it
will appear as a suggestion as they begin typing the same string of text. The screenshot below
shows an example of recent query suggestions.</p>
<p>Before you begin, you need to have implemented the Android search dialog for searches in your
application. If you haven't done this, see <a href="search-dialog.html">Using the Android Search
Dialog</a>.</p>
<h2 id="TheBasics">The Basics</h2>
<img src="{@docRoot}images/search/search-suggest-recent-queries.png" alt="" height="417"
style="float:right;clear:right;" />
<p>Recent query suggestions are simply saved searches. When the user selects one of
the suggestions, your searchable Activity will receive a normal {@link
android.content.Intent#ACTION_SEARCH} Intent with the suggestion as the search query, which your
searchable Activity will already handle.</p>
<p>To provide recent queries suggestions, you need to:</p>
<ul>
<li>Implement a basic searchable Activity, as documented in <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.</li>
<li>Save queries to your content provider each time a search is made.</li>
</ul>
<p>Just like the Search Manager handles the rendering of the search dialog, it will also do the work
to display all search suggestions below the search dialog. 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 also provides search
suggestions, the following procedure will take place as soon as the user types into the Android
search box:</p>
<ul>
<li>The Search Manager takes the search query text (whatever has been typed so far) and performs a
query to the content provider that manages your suggestions.</li>
<li>Your content provider then returns a {@link android.database.Cursor} that points to all
suggestions that are relevant to the search query text.</li>
<li>The Search Manager then displays the list of suggestions provided by the Cursor (as
demonstrated in the screenshot to the right).</li>
</ul>
<p>At this point, the following may 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, a normal
{@link android.content.Intent#ACTION_SEARCH} Intent is triggered, using the suggested text as the
query.</li>
</ul>
<p>As you'll soon discover, the {@link android.content.SearchRecentSuggestionsProvider} class that
you'll extend for your content provider will automatically do the work described above, so there's
actually very little code to write.</p>
<h2 id="RecentQuerySearchableConfiguration">Modifying the searchable configuration</h2>
<p>First, 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"
android:searchSuggestAuthority="my.package.MySuggestionProvider"
android:searchSuggestSelection=" ?" >
&lt;/searchable>
</pre>
<p>The value for {@code android:searchSuggestAuthority} should be a fully-qualified name for
your content provider: your application package name followed by the name of your content provider.
This string must match the authority used in the content provider (discussed in the next section).
</p>
<p>The value for {@code android:searchSuggestSelection} must be a single question-mark, preceded by
a space (" ?"), which is simply a placeholder for the SQLite selection argument (which will be
automatically replaced by the query text entered by the user).</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 = "my.package.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)}
passes the name of the search authority (matching the one in the searchable configuration) and a
database mode. The database mode must include {@link
android.content.SearchRecentSuggestionsProvider#DATABASE_MODE_QUERIES} and can optionally include
{@link
android.content.SearchRecentSuggestionsProvider#DATABASE_MODE_2LINES}, which will add another column
to the suggestions table that allows you to provide a second line of text with each suggestion. For
example:</p>
<pre>
public final static int MODE = DATABASE_MODE_QUERIES | DATABASE_MODE_2LINES;
</pre>
<p>In the following section, you'll see how to save both lines of text.</p>
<p>Now simply declare the content provider in your application manifest with the same authority
string used in the class (and in the searchable configuration). For example:</p>
<pre>
&lt;application>
&lt;provider android:name=".MySuggestionProvider"
android:authorities="my.package.authority" />
...
&lt;/application>
</pre>
<h2 id="SavingQueries">Saving queries</h2>
<p>In order to populate your collection of recent queries, you need to add each query
received by your searchable Activity to the content provider you've just built. To do this, create
an instance of {@link
android.provider.SearchRecentSuggestions} and call {@link
android.provider.SearchRecentSuggestions#saveRecentQuery(String,String)} 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>Notice that 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)} method takes
the search query string as the first parameter and, optionally, a second string to include as the
second line of the suggestion. 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 will be matched against this second line as well.</p>
<p>That's all that's needed to build a recent queries suggestion provider. However, there's one
other important thing to do: provide the ability for the user to clear this search history.</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 recent queries, simply call {@link
android.provider.SearchRecentSuggestions#clearHistory()}. For example:</p>
<pre>
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
HelloSuggestionProvider.AUTHORITY, HelloSuggestionProvider.MODE);
suggestions.clearHistory();
</pre>
<p>Simply execute this from your choice of a "Clear Search History" menu item,
preference item, or button. You should also provide a confirmation dialog when this is pressed, to
verify that the user wants to delete their search history.</p>

View File

@@ -0,0 +1,111 @@
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>See also</h2>
<ol>
<li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable
Dictionary sample app</a></li>
</ol>
</div>
</div>
<p>The ability to search is considered to be a core user feature on Android. The user should be able
to search any data that is available to them, whether the content is located on the device or the
Internet. This experience should be seamless and consistent across the entire
system, which is why Android provides a simple search framework to help you provide users with
a familiar search dialog and a great search experience.</p>
<img src="{@docRoot}images/search/search-suggest-custom.png" alt="" height="417"
style="float:right;clear:right;" />
<p>Android's search framework provides a user interface in which the user can perform a search and
an interaction layer that communicates with your application. This way, you don't have to build
a search box that the user must find in order to begin a search. Instead,
a custom search dialog will appear at the top of the screen at the user's command.
The search framework will manage the search dialog and when the user executes their search, the
search framework will pass the query text to your application so that your application can begin a
search. The screenshot to the right shows an example of the search dialog (using
search suggestions).</p>
<p>Once your application is set up to use the search dialog, you can:</p>
<ul>
<li>Customize some of the search dialog characteristics</li>
<li>Enable voice search</li>
<li>Provide search suggestions based on recent user queries</li>
<li>Provide 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>The following documents will teach 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 for searches. </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>
</dl>
<p>Also, the <strong><a href="searchable-config.html">Searchable Configuration</a></strong> document
provides a reference for the searchable configuration file (though the above
documents also discuss the configuration file in terms of specific behaviors).</p>
<p class="note"><strong>Note</strong>: The search framework does <em>not</em> provide APIs to
perform searches on your data. Performing actual searches is a task that you must accomplish
using APIs appropriate for your data, such as those in {@link android.database.sqlite}
if your data is in an SQLite database.</p>
<h2>Protecting User Privacy</h2>
<p>When you implement search in your application, you should take steps to protect the user's
privacy whenever possible. Many users consider their activities on the phone, including searches, to
be private information. To protect the user's privacy, you should abide by the following
principles:</p>
<ul>
<li><strong>Don't send personal information to servers, and if you do, don't log it.</strong>
<p>"Personal information" is information that can personally identify your users, such as their
name, email address, billing information, or other data which can be reasonably linked to such
information. If
your application implements search with the assistance of a server, try to 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 &mdash; send only the zip code to the server. If you must
send the personal information, you should take steps to avoid logging it. If you must log it, you
should 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 they type.
Sometimes these
suggestions are based on previous searches, or other actions taken by the user in an earlier
session. A user may not wish for previous searches to be revealed to other users, for instance if
they share their phone with a friend. If your application provides suggestions that can reveal
previous activities, you should implement a "Clear History" menu item, preference, or button. If you
are
using {@link android.provider.SearchRecentSuggestions}, you can simply call its {@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 can be invoked by the user.</p>
</li>
</ul>

View File

@@ -0,0 +1,542 @@
page.title=Using the Android Search Dialog
parent.title=Search
parent.link=index.html
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>Key classes</h2>
<ol>
<li>{@link android.app.SearchManager}</li>
</ol>
<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>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>
<li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable
Dictionary App</a></li>
</ol>
</div>
</div>
<p>When you want to provide search in your application, the last thing you should have to worry
about is where to put your search box. By using the Android search framework, your application will
reveal a custom search dialog whenever the user requests it. At the
press of a dedicated search key or an API call from your application, the search dialog will
appear at the top of the screen and will automatically show your application icon. An example is
shown in the screenshot below.</p>
<p>This guide will teach you how to set up your application to provide search in a custom search
dialog. In doing so, you will provide a standardized search experience and be able to add
features like voice search and search suggestions.</p>
<h2 id="TheBasics">The Basics</h2>
<img src="{@docRoot}images/search/search-ui.png" alt="" height="417"
style="float:right;clear:right;" />
<p>The Android search framework will manage the search dialog on your behalf; you never need
to draw it or worry about where it is, and your current Activity will not be
interrupted. The {@link android.app.SearchManager} is the component that does this work for
you (hereafter, referred to as "the Search Manager"). It manages the life of the Android search
dialog and will send your application the search query when executed by the user.</p>
<p>When the user executes a search, the Search Manager will use a specially-formed Intent to pass
the search query to the Activity that you've declared to handle searches. Essentially, all you
need is an Activity that receives this Intent, performs the search, and presents the results.
Specifically, what you need is the following:</p>
<dl>
<dt>A searchable configuration</dt>
<dd>This is an XML file that configures the search dialog and includes settings for
features such as the hint text shown in text box and settings voice search and search
suggestion.</dd>
<dt>A searchable Activity</dt>
<dd>This is 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>By default, the device search key (if available) will invoke the search dialog once
you've configured a searchable Activity. However, you should always provide another means by
which the user can invoke a search, such as with a search button in the Options Menu or elsewhere in
the Activity UI, because not all devices provide a dedicated search key.</dd>
</dl>
<h2 id="SearchableConfiguration">Creating a Searchable Configuration</h2>
<p>The searchable configuration is an XML file that defines several settings for the Android 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" >
&lt;/searchable>
</pre>
<p>This is the minimum configuration required in order to provide the search dialog. The {@code
android:label} attribute is the only required attribute and points to a string resource, which
should normally be the same as the application. (Although it's required, this
label isn't actually shown to the user until you enable suggestions for Quick Search Box.)</p>
<p>There are several other attributes accepted by the {@code &lt;searchable&gt;} element. Most of
which apply only when configuring features such as search suggestions and voice
search. However, we recommend that you always include the {@code android:hint} attribute, which
specifies a string resource for the text to display in the search dialog's text box before the user
enters their query&mdash;it provides important clues to the user 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>Next, you'll hook this configuration into your application.</p>
<h2 id="SearchableActivity">Creating a Searchable Activity</h2>
<p>When the user executes a search from the search dialog, the Search Manager will send
your searchable {@link android.app.Activity} the search query with the {@link
android.content.Intent#ACTION_SEARCH} {@link android.content.Intent}. Your searchable Activity will
then search your data and present the results.</p>
<h3 id="DeclaringSearchableActivity">Declaring a searchable Activity</h3>
<p>If you don't have one already, create an {@link android.app.Activity} that will be used to
perform searches, then declare it to
accept the {@link android.content.Intent#ACTION_SEARCH} {@link android.content.Intent} and apply the
searchable configuration. To do so, you need to add an {@code
&lt;intent-filter&gt;} element and a {@code &lt;meta-data&gt;} element to the
appropriate {@code &lt;activity&gt;} element in your manifest file. 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 android:name} attribute in the {@code &lt;meta-data&gt;} element must be defined with
{@code "android.app.searchable"} and the {@code android:resource} attribute value must be a
reference to the searchable configuration file saved in {@code res/xml} (in this example, it
refers to the {@code res/xml/searchable.xml} file).</p>
<p class="note">If you're wondering why the {@code
&lt;intent-filter&gt;} does not include a {@code &lt;category&gt;} with the {@code DEFAULT}
value, it's because the Intent that is delivered to this Activity when a search is executed will
explicitly define this Activity as the component for the Intent (which the Search Manager knows
from the searcahble meta-data declared for the Activity).</p>
<p>Be aware that the search dialog will not be available from within every
Activity of your application, by default. Rather, the search dialog will be 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 contains searchable meta-data that defines the
searchable configuration. Any other Activity in your application is not a searchable context, by
default, and thus, will not reveal the search dialog. You probably do want the
search dialog to be available from every Activity in your application, so this can be easily
fixed.</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;!-- this one declares the searchable Activity for the whole app --&gt;
&lt;meta-data android:name="android.app.default_searchable"
android:value=".MySearchableActivity" />
...
&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} will
be launched to handle the search query.</p>
<p>Notice that this allows you to control which activities provide search at a more granular level.
To specify only an individual Activity as a searchable context, simply 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;}). And, while it is uncommon, you can
even 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 declaring a default searchable Activity for the entire application and then overriding
it with a different {@code &lt;meta-data&gt;} element inside certain activities.</p>
<h3 id="PerformingSearch">Performing a search</h3>
<p>Once your Activity is declared searchable, performing the actual search involves three steps:
receiving the query, searching your data, and presenting the results.</p>
<p>Traditionally, your search results should be presented in a {@link android.widget.ListView}
(assuming that our results are text-based), so
you may 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 search is executed from the search dialog, your searchable Activity will be opened
with the {@link android.content.Intent#ACTION_SEARCH} {@link android.content.Intent}, which carries
the search query in the
{@link android.app.SearchManager#QUERY QUERY} extra. All you need to do is check for
this Intent and extract the string. For example, here's how you can get the query when your
Activity launches:</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 a process that's unique to your application.
There are many ways that you might do this and discussing all options is beyond the scope of
this document. This guide will not teach you how to store your data and search it; this
is something you must carefully consider in terms of your needs and your data. However, here are
some tips you may 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 many, many times 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 may be
inhibited by the user's data connection. You may want to display a spinning progress wheel until
your search returns. See {@link android.net} for a reference of network APIs and <a
href="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 will bind 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 a
version of the Searchable Dictionary that 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 easily 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 and not something covered by the search
framework APIs. However, a simple solution is to create your searchable Activity to extend {@link
android.app.ListActivity} and then call {@link
android.app.ListActivity#setListAdapter(ListAdapter)}, passing it an {@link
android.widget.Adapter} that is bound to your data. This will automatically project 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
application for an a complete demonstration of how to search an SQLite database and use an
{@link android.widget.Adapter} to provide resuls in a {@link android.widget.ListView}.</p>
<h2 id="InvokingTheSearchDialog">Invoking the Search Dialog</h2>
<p>Once you have a searchable Activity in place, invoking the search dialog so the user can
submit a
query is easy. Many Android devices provide a dedicated search key and when it is pressed while the
user is within a searchable context of your application, the search dialog will be revealed.
However,
you should never assume that a search key is available on the user's device and should always
provide a search button in your UI that will invoke search.</p>
<p>To invoke search from your Activity, simply call {@link
android.app.Activity#onSearchRequested()}.</p>
<p>For example, 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. For your convenience, this <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 menu item or button (low density
screens will 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 in your Activity by calling {@link
android.app.Activity#setDefaultKeyMode(int) setDefaultKeyMode}({@link
android.app.Activity#DEFAULT_KEYS_SEARCH_LOCAL}). When this is enabled and the user begins typing on
the keyboard, search will automatically be
invoked and the keystrokes will be inserted in the search dialog. Be sure to enable this mode
during your Activity {@link android.app.Activity#onCreate(Bundle) onCreate()} method.</p>
<h3 id="LifeCycle">The impact of the search dialog on your Activity life-cycle</h3>
<p>The search dialog behaves like a {@link android.app.Dialog} that floats at the top of the
screen. It
does not cause any change in the Activity stack, so no life-cycle methods (such as {@link
android.app.Activity#onPause()}) will
be called. All that happens is your Activity loses input focus as it is given to the search dialog.
</p>
<p>If you want to be notified when search is invoked, simply override the {@link
android.app.Activity#onSearchRequested()} method. When this is called, you can do any work you may
want to do when your Activity looses input focus (such as pause animations). But unless you are
<a href="#SearchContextData">Passing Search Context Data</a> (discussed above), you should always
call 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 device Back key, the Activity in which search was
invoked will re-gain input focus. You can register to be notified when the search dialog is
closed with {@link android.app.SearchManager#setOnDismissListener(SearchManager.OnDismissListener)}
and/or {@link android.app.SearchManager#setOnCancelListener(SearchManager.OnCancelListener)}. You
should normally only need to register the {@link android.app.SearchManager.OnDismissListener
OnDismissListener}, because this is called every time that the search dialog is closed. The {@link
android.app.SearchManager.OnCancelListener OnCancelListener} only pertains to events in which the
user explicitly left 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 life-cycle
events will be triggered once the user executes a search (the current Activity will receive {@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 will happen:</p>
<ul>
<li>By default, the searchable Activity will receive 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 will be brought to the top of the stack. You'll now have two instances of your searchable
Activity in the Activity stack (so pressing the Back key will go back to the previous instance of
the searchable Activity, rather than exiting the searchable Activity).</li>
<li>On the other hand, if the Activity has set {@code android:launchMode} to "singleTop" then the
searchable Activity will receive 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 want to handle
this case:
<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="#PerfomingSearch">Performing a
Search</a>, all the code to handle the
search Intent has been moved outside the {@link android.app.Activity#onCreate(Bundle)
onCreate()} method so it can also be executed from {@link android.app.Activity#onNewIntent(Intent)
onNewIntent()}.
It's important to note that when {@link android.app.Activity#onNewIntent(Intent)} is
called, the Activity has not been restarted, so the {@link android.app.Activity#getIntent()} method
will still return the Intent that was first received with {@link
android.app.Activity#onCreate(Bundle) onCreate()}. This is why {@link
android.app.Activity#setIntent(Intent)} is called inside {@link
android.app.Activity#onNewIntent(Intent)} (just in case you call {@link
android.app.Activity#getIntent()} at a later time).</p>
</li>
</ul>
<p>This second scenario is normally ideal, because the chances are good that once a search is
completed, the user will perform additional searches and it's a bad experience if your application
piles multiple instances of the searchable Activity on the stack. 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"
android:launchMode="singleTop" >
&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>In order to refine your search criteria, you may want to provide some additional
data to your searchable Activity when a search is executed. For instance, when you search your data,
you may want to filter results based on more than just the search query text. In a simple
case, you could just make your refinements inside the searchable Activity, for every search made.
If, however, your
search criteria may vary 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} 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, you need to override {@link
android.app.Activity#onSearchRequested()} method for the Activity in which search will 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 this data 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>Note:</strong> You should never call the {@link
android.app.Activity#startSearch(String,boolean,Bundle,boolean) startSearch()} method from outside
the {@link android.app.Activity#onSearchRequested()} callback method. When you want to invoke the
search dialog, always call {@link android.app.Activity#onSearchRequested()} so that custom
implementations (such as the addition of {@code appData}, in the above example) can be accounted
for.</p>
<h2 id="VoiceSearch">Adding Voice Search</h2>
<p>You can easily add voice search functionality to your search dialog by adding the {@code
android:voiceSearchMode} attribute to your searchable configuration. This will add a voice search
button in the search dialog that, when clicked, will launch a voice prompt. When the user
has finished speaking, the transcribed search query will be sent to your searchable
Activity.</p>
<p>To enable voice search for your activity, add the {@code android:voiceSearchMode}
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/search_label"
android:hint="@string/search_hint"
android:voiceSearchMode="showVoiceSearchButton|launchRecognizer" >
&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. This is
how most applications should declare this attribute.</p>
<p>There are some additional attributes you can provide 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> 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 will be immediately sent to
your searchable Activity without a chance for the user to review the transcribed query. Be sure to
sufficiently test the voice recognition and ensure that it understands the types of queries that
the user will submit inside your application.</p>

View File

@@ -0,0 +1,356 @@
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>In order 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 a more complete discussion about how to implement search
features for your application, see the companion documents 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/>
The filename will be used 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>. <strong>Required</strong>. This is the name of your application.
It should normally 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 is only visible to the user when you set
<code>android:includeInGlobalSearch</code> "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>. The text to display in the search text field when no text has
been entered. This is recommended in order to provide a hint to the user about what
content is searchable. 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".</dd>
<dt><code>android:searchMode</code></dt>
<dd><em>Keyword</em>. Sets additional modes that control the search presentation.
Specifically, the available modes define how the query text in the search dialog's text box
should be rewritten when a suggestion is focused. The following mode values are accepted:
<table>
<tr><th>Value</th><th>Description</th></tr>
<tr>
<td><code>"queryRewriteFromData"</code></td>
<td>If set, this causes the suggestion column
{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} to be considered as the
text for suggestion query
rewriting. 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/HTTPS Uri's.</td>
</tr>
<tr>
<td><code>"queryRewriteFromText"</code></td>
<td>If set, this causes the suggestion
column {@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1} to be considered as the
text for suggestion query
rewriting. This should be used for suggestions in which no query
text is provided and the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA}
values are not suitable
for user inspection and editing.</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 the search. By
default, the button shows a search icon (a magnifying glass), which is ideal for
internationalization.</dd>
<dt><code>android:inputType</code></dt>
<dd><em>Keyword</em>. Defines the type of input method (soft-keyboard) to use with the search
dialog. For most searches, in which free form text is expected, this attribute is not needed and
the default input method should be used. 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, this attribute is not needed,
and will default to "actionSearch" (provides the "search" button instead of a carriage
return). See {@link android.R.attr#imeOptions} for a list of suitable values for this attribute.
</dd>
</dl>
<p>If you have defined a content provider to generate search suggestions, you need to
define additional attributes in order to configure communications with the Content
Provider. When providing search suggestions, you'll 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>. <strong>Required to provide search suggestions</strong>.
This value must match the authority string provided in the {@code android:authorities}
attribute of the {@code &lt;provider>} element.</dd>
<dt><code>android:searchSuggestPath</code></dt>
<dd><em>String</em>. This path will be 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 (e.g. for different data types) and you need
a way to disambiguate the suggestions queries when they are received.</dd>
<dt><code>android:searchSuggestSelection</code></dt>
<dd><em>String</em>. This value will be passed into your
query function as the {@code selection} parameter. Typically this will be a WHERE clause
for your database, and should contain a single question mark, which is a place-holder for the
actual query string that has been typed by the user. However, you can also use any non-null
value to simply 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 search suggestion (such as {@code "android.intent.action.VIEW"}).
If not overridden by the selected suggestion (via the {@link
android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column), this value will
be 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 search suggestion.
If not overridden by the selected suggestion (via the {@link
android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column), this value will be
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 a source will not be
queried 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>
<p>Beyond providing search suggestions while using your application's search dialog, you
can also configure your search suggestions to be made available to Quick Search Box,
which will allow users so receive search suggestions from your application content from outside
your application. When providing search suggestions to Quick Search Box, you'll 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>. <strong>Required to provide search suggestions in
Quick Search Box</strong>. "true" if you want your suggestions to be
included in the globally accessible Quick Search Box. Note that the user must
still enable your application as a searchable item in the system search settings in order
for your suggestions to 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 will be 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>. "true" if you want your content provider to be invoked for
supersets of queries that have returned zero results for in the past. For example, if a
source returned zero results for "bo", it would be ignored for "bob". If "false",
this source will only be ignored for a single session; the next time the search dialog
is invoked, all sources will be queried. The default value is false.</dd>
</dl>
<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>. <strong>Required to provide voice search capabilities</strong>.
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 will
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. This only
takes effect 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 will take the user directly
to a built-in voice web search activity. Most applications will not use this flag, as
it will take the user away from the Activity in which search was invoked.</td>
</tr>
<tr>
<td><code>"launchRecognizer"</code></td>
<td>The voice search button will take
the user directly to a built-in voice recording activity. This Activity
will prompt the user to speak, transcribe the spoken text, and forward the resulting
query text to the searchable Activity, just as if the user had 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 a language model based on free-form speech recognition. This is the
default.</td>
</tr>
<tr>
<td><code>"web_search"</code></td>
<td>Use a language model based on web search terms.</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} (for example, {@code "de"} for German or {@code "fr"} for
French). This is only needed 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 will always be 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 will choose how many results to return.</dd>
</dl>
</dd> <!-- end searchable element -->
<dt id="actionkey-element"><code>&lt;actionkey&gt;</code></dt>
<dd>Defines a shortcut key for a search action, in order to provide special behaviors at the touch
of a button, based on the current query or selected suggestion. For example, the Contacts
application enables the device call key for suggestions. So, when
the user focuses on a search suggestion using the directional controls and then presses the call
key, the application will immediately initiate a phone call to the suggested contact. See the
{@link android.app.SearchManager} for more information about action keys.
<p class="caps">attributes:</p>
<dl class="atn-list">
<dt><code>android:keycode</code></dt>
<dd><em>String</em>. <strong>Required</strong>. A key code from {@link
android.view.KeyEvent} that represents the action key
you wish to respond to (for example {@code "KEYCODE_CALL"}). This will be 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)}.
In addition to the key code, you must also provide one or more of
the action specifier attributes below. Not all action keys
are actually supported using this mechanism, as many of them are used for typing,
navigation, or system functions. Note that although each of the action message elements are
optional, at least one must be present for the action key to have any effect.</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 simply entering query text. This will be added to the
{@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} Intent that is
passed 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 being displayed and is currently selected. This will be added to the
Intent that is passed 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)}. Note that 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 action key is pressed while a
suggestion is being displayed and is currently selected. 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. 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 will look at your suggestion cursor,
using the string provided here in order to select your action message column, and
then select the action message string from the cursor. That string will be added to the
Intent that is passed 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 will be 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.