blob: 47ad2fec9a1244ae20915a3c9dfb6c5a1cad82d9 [file] [log] [blame]
Scott Mainb3b2b4f2010-02-12 17:19:02 -08001page.title=Adding Custom Suggestions
Scott Main64461bf2013-04-11 19:32:08 -07002page.tags="SearchRecentSuggestionsProvider",
Scott Mainb3b2b4f2010-02-12 17:19:02 -08003@jd:body
4
5<div id="qv-wrapper">
6<div id="qv">
Scott Mainb3b2b4f2010-02-12 17:19:02 -08007<h2>In this document</h2>
8<ol>
9<li><a href="#TheBasics">The Basics</a></li>
Scott Main5e892d82010-05-25 17:04:01 -070010<li><a href="#CustomSearchableConfiguration">Modifying the Searchable Configuration</a></li>
Scott Mainb3b2b4f2010-02-12 17:19:02 -080011<li><a href="#CustomContentProvider">Creating a Content Provider</a>
12 <ol>
13 <li><a href="#HandlingSuggestionQuery">Handling a suggestion query</a></li>
14 <li><a href="#SuggestionTable">Building a suggestion table</a></li>
15 </ol>
16</li>
Scott Main5e892d82010-05-25 17:04:01 -070017<li><a href="#IntentForSuggestions">Declaring an Intent for Suggestions</a>
Scott Mainb3b2b4f2010-02-12 17:19:02 -080018 <ol>
Scott Mainabdf0d52011-02-08 10:20:27 -080019 <li><a href="#IntentAction">Declaring the intent action</a></li>
20 <li><a href="#IntentData">Declaring the intent data</a></li>
Scott Mainb3b2b4f2010-02-12 17:19:02 -080021 </ol>
22</li>
23<li><a href="#HandlingIntent">Handling the Intent</a></li>
Scott Main5e892d82010-05-25 17:04:01 -070024<li><a href="#RewritingQueryText">Rewriting the Query Text</a></li>
25<li><a href="#QSB">Exposing Search Suggestions to Quick Search Box</a></li>
Scott Mainb3b2b4f2010-02-12 17:19:02 -080026</ol>
Scott Main5e892d82010-05-25 17:04:01 -070027
28<h2>Key classes</h2>
29<ol>
30<li>{@link android.app.SearchManager}</li>
31<li>{@link android.content.SearchRecentSuggestionsProvider}</li>
32<li>{@link android.content.ContentProvider}</li>
33</ol>
34
Scott Mainec80d7f2010-09-24 16:17:27 -070035<h2>Related samples</h2>
Scott Main5e892d82010-05-25 17:04:01 -070036<ol>
37<li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable
38Dictionary</a></li>
39</ol>
40
Scott Mainb3b2b4f2010-02-12 17:19:02 -080041<h2>See also</h2>
42<ol>
43<li><a href="searchable-config.html">Searchable Configuration</a></li>
44<li><a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a></li>
Scott Mainb3b2b4f2010-02-12 17:19:02 -080045</ol>
46</div>
47</div>
48
Scott Mainabdf0d52011-02-08 10:20:27 -080049<p>When using the Android search dialog or search widget, you can provide custom search suggestions
50that are created from data in your application. For example, if your application is a word
Scott Main5e892d82010-05-25 17:04:01 -070051dictionary, you can suggest words from the
52dictionary that match the text entered so far. These are the most valuable suggestions, because you
53can effectively predict what the user wants and provide instant access to it. Figure 1 shows
54an example of a search dialog with custom suggestions.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -080055
Scott Main5e892d82010-05-25 17:04:01 -070056<p>Once you provide custom suggestions, you can also make them available to the system-wide Quick
57Search Box, providing access to your content from outside your application.</p>
58
59<p>Before you begin with this guide to add custom suggestions, you need to have implemented the
Scott Mainabdf0d52011-02-08 10:20:27 -080060Android search dialog or a search widget for searches in your
61application. If you haven't, see <a href="search-dialog.html">Creating a Search Interface</a>.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -080062
63
64<h2 id="TheBasics">The Basics</h2>
65
Scott Main5e892d82010-05-25 17:04:01 -070066<div class="figure" style="width:250px">
67<img src="{@docRoot}images/search/search-suggest-custom.png" alt="" height="417" />
68<p class="img-caption"><strong>Figure 1.</strong> Screenshot of a search dialog with custom
69search suggestions.</p>
70</div>
Scott Mainb3b2b4f2010-02-12 17:19:02 -080071
Scott Mainabdf0d52011-02-08 10:20:27 -080072<p>When the user selects a custom suggestion, the Android system sends an {@link
Scott Main5e892d82010-05-25 17:04:01 -070073android.content.Intent} to
Scott Mainabdf0d52011-02-08 10:20:27 -080074your searchable activity. Whereas a normal search query sends an intent with the {@link
Scott Mainb3b2b4f2010-02-12 17:19:02 -080075android.content.Intent#ACTION_SEARCH} action, you can instead define your custom suggestions to use
Scott Mainabdf0d52011-02-08 10:20:27 -080076{@link android.content.Intent#ACTION_VIEW} (or any other intent action), and also include data
Scott Mainb3b2b4f2010-02-12 17:19:02 -080077that's relevant to the selected suggestion. Continuing
78the dictionary example, when the user selects a suggestion, your application can immediately
79open the definition for that word, instead of searching the dictionary for matches.</p>
80
Scott Main5e892d82010-05-25 17:04:01 -070081<p>To provide custom suggestions, do the following:</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -080082
83<ul>
Scott Mainabdf0d52011-02-08 10:20:27 -080084 <li>Implement a basic searchable activity, as described in <a
85href="search-dialog.html">Creating a Search Interface</a>.</li>
Scott Main5e892d82010-05-25 17:04:01 -070086 <li>Modify the searchable configuration with information about the content provider that
87provides custom suggestions.</li>
Scott Mainb3b2b4f2010-02-12 17:19:02 -080088 <li>Build a table (such as in an {@link android.database.sqlite.SQLiteDatabase}) for your
89suggestions and format the table with required columns.</li>
90 <li>Create a <a href="{@docRoot}guide/topics/providers/content-providers.html">Content
91Provider</a> that has access to your suggestions table and declare the provider
92in your manifest.</li>
93 <li>Declare the type of {@link android.content.Intent} to be sent when the user selects a
94suggestion (including a custom action and custom data). </li>
Scott Mainb3b2b4f2010-02-12 17:19:02 -080095</ul>
96
Scott Mainabdf0d52011-02-08 10:20:27 -080097<p>Just as the Android system displays the search dialog, it also displays your search
98suggestions. All you need is a content provider from which the system can retrieve your
Scott Main5e892d82010-05-25 17:04:01 -070099suggestions. If you're not familiar with creating content
100providers, read the <a href="{@docRoot}guide/topics/providers/content-providers.html">Content
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800101Providers</a> developer guide before you continue.</p>
102
Scott Mainabdf0d52011-02-08 10:20:27 -0800103<p>When the system identifies that your activity is searchable and provides search
104suggestions, the following procedure takes place when the user types a query:</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800105
Scott Main5e892d82010-05-25 17:04:01 -0700106<ol>
Scott Mainabdf0d52011-02-08 10:20:27 -0800107 <li>The system takes the search query text (whatever has been typed so far) and performs a
Scott Main5e892d82010-05-25 17:04:01 -0700108query to your content provider that manages your suggestions.</li>
109 <li>Your content provider returns a {@link android.database.Cursor} that points to all
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800110suggestions that are relevant to the search query text.</li>
Scott Mainabdf0d52011-02-08 10:20:27 -0800111 <li>The system displays the list of suggestions provided by the Cursor.</li>
Scott Main5e892d82010-05-25 17:04:01 -0700112</ol>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800113
Scott Main5e892d82010-05-25 17:04:01 -0700114<p>Once the custom suggestions are displayed, the following might happen:</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800115
116<ul>
117 <li>If the user types another key, or changes the query in any way, the above steps are repeated
118and the suggestion list is updated as appropriate. </li>
Scott Main5e892d82010-05-25 17:04:01 -0700119 <li>If the user executes the search, the suggestions are ignored and the search is delivered
Scott Mainabdf0d52011-02-08 10:20:27 -0800120to your searchable activity using the normal {@link android.content.Intent#ACTION_SEARCH}
121intent.</li>
122 <li>If the user selects a suggestion, an intent is sent to your searchable activity, carrying a
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800123custom action and custom data so that your application can open the suggested content.</li>
124</ul>
125
126
127
128<h2 id="CustomSearchableConfiguration">Modifying the searchable configuration</h2>
129
130<p>To add support for custom suggestions, add the {@code android:searchSuggestAuthority} attribute
131to the {@code &lt;searchable&gt;} element in your searchable configuration file. For example:</p>
132
133<pre>
Scott Main5e892d82010-05-25 17:04:01 -0700134&lt;?xml version="1.0" encoding="utf-8"?&gt;
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800135&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
136 android:label="@string/app_label"
137 android:hint="@string/search_hint"
Scott Main5e892d82010-05-25 17:04:01 -0700138 <b>android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"</b>&gt;
139&lt;/searchable&gt;
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800140</pre>
141
Scott Mainabdf0d52011-02-08 10:20:27 -0800142<p>You might need some additional attributes, depending on the type of intent you attach
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800143to each suggestion and how you want to format queries to your content provider. The other optional
Scott Main5e892d82010-05-25 17:04:01 -0700144attributes are discussed in the following sections.</p>
145
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800146
147
148<h2 id="CustomContentProvider">Creating a Content Provider</h2>
149
Scott Main5e892d82010-05-25 17:04:01 -0700150<p>Creating a content provider for custom suggestions requires previous knowledge about content
151providers that's covered in the <a
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800152href="{@docRoot}guide/topics/providers/content-providers.html">Content Provider</a> developer
153guide. For the most part, a content provider for custom suggestions is the
154same as any other content provider. However, for each suggestion you provide, the respective row in
Scott Mainabdf0d52011-02-08 10:20:27 -0800155the {@link android.database.Cursor} must include specific columns that the system
Scott Main5e892d82010-05-25 17:04:01 -0700156understands and uses to format the suggestions.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800157
Scott Mainabdf0d52011-02-08 10:20:27 -0800158<p>When the user starts typing into the search dialog or search widget, the system queries
159your content provider for suggestions by calling {@link
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800160android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} each time
161a letter is typed. In your implementation of {@link
162android.content.ContentProvider#query(Uri,String[],String,String[],String) query()}, your
163content provider must search your suggestion data and return a {@link
Scott Main5e892d82010-05-25 17:04:01 -0700164android.database.Cursor} that points to the rows you have determined to be good suggestions.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800165
Scott Main5e892d82010-05-25 17:04:01 -0700166<p>Details about creating a content provider for custom suggestions are discussed in the following
167two sections:</p>
168<dl>
169 <dt><a href="#HandlingSuggestionQuery">Handling the suggestion query</a></dt>
Scott Mainabdf0d52011-02-08 10:20:27 -0800170 <dd>How the system sends requests to your content provider and how to handle them</dd>
Scott Main5e892d82010-05-25 17:04:01 -0700171 <dt><a href="#SuggestionTable">Building a suggestion table</a></dt>
Scott Mainabdf0d52011-02-08 10:20:27 -0800172 <dd>How to define the columns that the system expects in the {@link
Scott Main5e892d82010-05-25 17:04:01 -0700173android.database.Cursor} returned with each query</dd>
174</dl>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800175
176
177<h3 id="HandlingSuggestionQuery">Handling the suggestion query</h3>
178
Scott Mainabdf0d52011-02-08 10:20:27 -0800179<p>When the system requests suggestions from your content provider, it calls your content
Scott Main5e892d82010-05-25 17:04:01 -0700180provider's {@link android.content.ContentProvider#query(Uri,String[],String,String[],String)
181query()} method. You must
182implement this method to search your suggestion data and return a
183{@link android.database.Cursor} pointing to the suggestions you deem relevant.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800184
Scott Mainabdf0d52011-02-08 10:20:27 -0800185<p>Here's a summary of the parameters that the system passes to your {@link
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800186android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method
187(listed in order):</p>
188
189<dl>
190 <dt><code>uri</code></dt>
Scott Main5e892d82010-05-25 17:04:01 -0700191 <dd>Always a content {@link android.net.Uri}, formatted as:
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800192<pre class="no-pretty-print">
193content://<em>your.authority</em>/<em>optional.suggest.path</em>/<em>{@link
194android.app.SearchManager#SUGGEST_URI_PATH_QUERY}</em>
195</pre>
Scott Mainabdf0d52011-02-08 10:20:27 -0800196<p>The default behavior is for system to pass this URI and append it with the query text.
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800197For example:</p>
198<pre class="no-pretty-print">
199content://<em>your.authority</em>/<em>optional.suggest.path</em>/<em>{@link
200android.app.SearchManager#SUGGEST_URI_PATH_QUERY}</em>/puppies
201</pre>
Scott Main5e892d82010-05-25 17:04:01 -0700202<p>The query text on the end is encoded using URI encoding rules, so you might need to decode
203it before performing a search.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800204<p>The <em>{@code optional.suggest.path}</em> portion is only included in the URI if you have set
205such a path in your searchable configuration file with the {@code android:searchSuggestPath}
206attribute. This is only needed if you use the same content provider for multiple searchable
Scott Main5e892d82010-05-25 17:04:01 -0700207activities, in which case, you need to disambiguate the source of the suggestion query.</p>
208<p class="note"><strong>Note:</strong> {@link
209android.app.SearchManager#SUGGEST_URI_PATH_QUERY} is not the literal
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800210string provided in the URI, but a constant that you should use if you need to refer to this
211path.</p>
212 </dd>
213
214 <dt><code>projection</code></dt>
Scott Main5e892d82010-05-25 17:04:01 -0700215 <dd>Always null</dd>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800216
217 <dt><code>selection</code></dt>
Scott Main5e892d82010-05-25 17:04:01 -0700218 <dd>The value provided in the {@code android:searchSuggestSelection} attribute of
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800219your searchable configuration file, or null if you have not declared the {@code
Scott Main5e892d82010-05-25 17:04:01 -0700220android:searchSuggestSelection} attribute. More about using this to <a href="#GetTheQuery">get the
221query</a> below.</dd>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800222
223 <dt><code>selectionArgs</code></dt>
Scott Main5e892d82010-05-25 17:04:01 -0700224 <dd>Contains the search query as the first (and only) element of the array if you have
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800225declared the {@code android:searchSuggestSelection} attribute in your searchable configuration. If
226you have not declared {@code android:searchSuggestSelection}, then this parameter is null. More
Scott Main5e892d82010-05-25 17:04:01 -0700227about using this to <a href="#GetTheQuery">get the query</a> below.</dd>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800228
229 <dt><code>sortOrder</code></dt>
Scott Main5e892d82010-05-25 17:04:01 -0700230 <dd>Always null</dd>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800231</dl>
232
Scott Mainabdf0d52011-02-08 10:20:27 -0800233<p>The system can send you the search query text in two ways. The
Scott Main5e892d82010-05-25 17:04:01 -0700234default manner is for the query text to be included as the last path of the content
235URI passed in the {@code uri} parameter. However, if you include a selection value in your
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800236searchable configuration's {@code
Scott Main5e892d82010-05-25 17:04:01 -0700237android:searchSuggestSelection} attribute, then the query text is instead passed as the first
238element of the {@code selectionArgs} string array. Both options are summarized next.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800239
240
Scott Main5e892d82010-05-25 17:04:01 -0700241<h4 id="GetTheQueryUri">Get the query in the Uri</h4>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800242
Scott Main5e892d82010-05-25 17:04:01 -0700243<p>By default, the query is appended as the last segment of the {@code uri}
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800244parameter (a {@link android.net.Uri} object). To retrieve the query text in this case, simply use
245{@link android.net.Uri#getLastPathSegment()}. For example:</p>
246
247<pre>
248String query = uri.getLastPathSegment().toLowerCase();
249</pre>
250
Scott Mainabdf0d52011-02-08 10:20:27 -0800251<p>This returns the last segment of the {@link android.net.Uri}, which is the query text entered
252by the user.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800253
254
255
Scott Main5e892d82010-05-25 17:04:01 -0700256<h4 id="GetTheQuery">Get the query in the selection arguments</h4>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800257
Scott Main5e892d82010-05-25 17:04:01 -0700258<p>Instead of using the URI, you might decide it makes more sense for your {@link
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800259android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method to
260receive everything it needs to perform the look-up and you want the
Scott Main5e892d82010-05-25 17:04:01 -0700261{@code selection} and {@code selectionArgs} parameters to carry the appropriate values. In such a
262case, add the {@code android:searchSuggestSelection} attribute to your searchable configuration with
263your SQLite selection string. In the selection string, include a question mark ("?") as
Scott Mainabdf0d52011-02-08 10:20:27 -0800264a placeholder for the actual search query. The system calls {@link
Scott Main5e892d82010-05-25 17:04:01 -0700265android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} with the
266selection string as the {@code selection} parameter and the search query as the first
267element in the {@code selectionArgs} array.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800268
269<p>For example, here's how you might form the {@code android:searchSuggestSelection} attribute to
270create a full-text search statement:</p>
271
272<pre>
Scott Main5e892d82010-05-25 17:04:01 -0700273&lt;?xml version="1.0" encoding="utf-8"?&gt;
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800274&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
275 android:label="@string/app_label"
276 android:hint="@string/search_hint"
Scott Main5e892d82010-05-25 17:04:01 -0700277 android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"
Scott Mainabdf0d52011-02-08 10:20:27 -0800278 android:searchSuggestIntentAction="android.intent.action.VIEW"
Scott Main5e892d82010-05-25 17:04:01 -0700279 <b>android:searchSuggestSelection="word MATCH ?"</b>&gt;
280&lt;/searchable&gt;
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800281</pre>
282
Scott Main5e892d82010-05-25 17:04:01 -0700283<p>With this configuration, your {@link
284android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method
Scott Mainabdf0d52011-02-08 10:20:27 -0800285delivers the {@code selection} parameter as {@code "word MATCH ?"} and the {@code selectionArgs}
286parameter as the search query. When you pass these to an SQLite
Scott Main5e892d82010-05-25 17:04:01 -0700287{@link android.database.sqlite.SQLiteDatabase#query(String,String[],String,String[],String,String,
288String) query()} method, as their respective arguments, they are synthesized together (the
289question mark is replaced with the query
290text). If you chose to receive suggestion queries this way and need to add wildcards to
291the query text, append (and/or prefix) them to the {@code selectionArgs}
292parameter, because this value is wrapped in quotes and inserted in place of the
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800293question mark.</p>
294
Scott Main5e892d82010-05-25 17:04:01 -0700295<p>Another new attribute in the example above is {@code android:searchSuggestIntentAction}, which
Scott Mainabdf0d52011-02-08 10:20:27 -0800296defines the intent action sent with each intent when the user selects a suggestion. It is
Scott Main5e892d82010-05-25 17:04:01 -0700297discussed further in the section about <a href="#IntentForSuggestions">Declaring an Intent for
Scott Mainabdf0d52011-02-08 10:20:27 -0800298Suggestions</a>.</p>
Scott Main5e892d82010-05-25 17:04:01 -0700299
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800300<p class="note"><strong>Tip:</strong> If you don't want to define a selection clause in
301the {@code android:searchSuggestSelection} attribute, but would still like to receive the query
302text in the {@code selectionArgs} parameter, simply provide a non-null value for the {@code
Scott Main5e892d82010-05-25 17:04:01 -0700303android:searchSuggestSelection} attribute. This triggers the query to be passed in {@code
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800304selectionArgs} and you can ignore the {@code selection} parameter. In this way, you can instead
305define the actual selection clause at a lower level so that your content provider doesn't have to
306handle it.</p>
307
308
309
310<h3 id="SuggestionTable">Building a suggestion table</h3>
311
312<div class="sidebox-wrapper">
313<div class="sidebox">
Scott Main5e892d82010-05-25 17:04:01 -0700314<h2>Creating a Cursor without a table</h2>
315<p>If your search suggestions are not stored in a table format (such as an SQLite table) using the
316columns required by the
Scott Mainabdf0d52011-02-08 10:20:27 -0800317system, then you can search your suggestion data for matches and then format them
Scott Main5e892d82010-05-25 17:04:01 -0700318into the necessary table on each request. To do so, create a {@link android.database.MatrixCursor}
319using the required column names and then add a row for each suggestion using {@link
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800320android.database.MatrixCursor#addRow(Object[])}. Return the final product from your Content
321Provider's {@link
322android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method.</p>
323</div>
324</div>
325
Scott Mainabdf0d52011-02-08 10:20:27 -0800326<p>When you return suggestions to the system with a {@link android.database.Cursor}, the
327system expects specific columns in each row. So, regardless of whether you
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800328decide to store
329your suggestion data in an SQLite database on the device, a database on a web server, or another
330format on the device or web, you must format the suggestions as rows in a table and
Scott Mainabdf0d52011-02-08 10:20:27 -0800331present them with a {@link android.database.Cursor}. The system understands several columns, but
332only two are required:</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800333
334<dl>
335 <dt>{@link android.provider.BaseColumns#_ID}</dt>
Scott Mainabdf0d52011-02-08 10:20:27 -0800336 <dd>A unique integer row ID for each suggestion. The system requires this in order
337to present suggestions in a {@link android.widget.ListView}.</dd>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800338 <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}</dt>
Scott Main5e892d82010-05-25 17:04:01 -0700339 <dd>The string that is presented as a suggestion.</dd>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800340</dl>
341
Scott Main5e892d82010-05-25 17:04:01 -0700342<p>The following columns are all optional (and most are discussed further in the following
343sections):</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800344
345<dl>
346 <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_2}</dt>
Scott Main5e892d82010-05-25 17:04:01 -0700347 <dd>A string. If your Cursor includes this column, then all suggestions are provided in a
348two-line format. The string in this column is displayed as a second, smaller line of text below the
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800349primary suggestion text. It can be null or empty to indicate no secondary text.</dd>
350 <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_ICON_1}</dt>
Scott Main5e892d82010-05-25 17:04:01 -0700351 <dd>A drawable resource, content, or file URI string. If your Cursor includes this column, then
352all suggestions are provided in an icon-plus-text format with the drawable icon on the left side.
353This can be null or zero to indicate no icon in this row.</dd>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800354 <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_ICON_2}</dt>
Scott Main5e892d82010-05-25 17:04:01 -0700355 <dd>A drawable resource, content, or file URI string. If your Cursor includes this column, then
356all suggestions are provided in an icon-plus-text format with the icon on the right side. This can
357be null or zero to indicate no icon in this row.</dd>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800358 <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION}</dt>
Scott Mainabdf0d52011-02-08 10:20:27 -0800359 <dd>An intent action string. If this column exists and contains a value at the given row, the
360action defined here is used when forming the suggestion's intent. If the element is not
Scott Main5e892d82010-05-25 17:04:01 -0700361provided, the action is taken from the {@code android:searchSuggestIntentAction} field in your
362searchable configuration. If your action is the same for all
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800363suggestions, it is more efficient to specify the action using {@code
Scott Main5e892d82010-05-25 17:04:01 -0700364android:searchSuggestIntentAction} and omit this column.</dd>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800365 <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA}</dt>
Scott Main5e892d82010-05-25 17:04:01 -0700366 <dd>A data URI string. If this column exists and contains a value at the given row, this is the
Scott Mainabdf0d52011-02-08 10:20:27 -0800367data that is used when forming the suggestion's intent. If the element is not provided, the data is
Scott Main5e892d82010-05-25 17:04:01 -0700368taken from the {@code android:searchSuggestIntentData} field in your searchable configuration. If
369neither source is provided,
Scott Mainabdf0d52011-02-08 10:20:27 -0800370the intent's data field is null. If your data is the same for all suggestions, or can be
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800371described using a constant part and a specific ID, it is more efficient to specify it using {@code
Scott Main5e892d82010-05-25 17:04:01 -0700372android:searchSuggestIntentData} and omit this column.
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800373</dd>
374 <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID}</dt>
Scott Main5e892d82010-05-25 17:04:01 -0700375 <dd>A URI path string. If this column exists and contains a value at the given row, then "/" and
Scott Mainabdf0d52011-02-08 10:20:27 -0800376this value is appended to the data field in the intent. This should only be used if the data field
Scott Main5e892d82010-05-25 17:04:01 -0700377specified
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800378by the {@code android:searchSuggestIntentData} attribute in the searchable configuration has already
379been set to an appropriate base string.</dd>
380 <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_EXTRA_DATA}</dt>
Scott Main5e892d82010-05-25 17:04:01 -0700381 <dd>Arbitrary data. If this column exists and contains a value at a given row, this is the
Scott Mainabdf0d52011-02-08 10:20:27 -0800382<em>extra</em> data used when forming the suggestion's intent. If not provided, the
383intent's extra data field is null. This column allows suggestions to provide additional data that is
384included as an extra in the intent's {@link android.app.SearchManager#EXTRA_DATA_KEY} key.</dd>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800385 <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_QUERY}</dt>
Scott Main5e892d82010-05-25 17:04:01 -0700386 <dd>If this column exists and this element exists at the given row, this is the data that is
Scott Mainabdf0d52011-02-08 10:20:27 -0800387used when forming the suggestion's query, included as an extra in the intent's {@link
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800388android.app.SearchManager#QUERY} key. Required if suggestion's action is {@link
389android.content.Intent#ACTION_SEARCH}, optional otherwise.</dd>
390 <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID}</dt>
Scott Main5e892d82010-05-25 17:04:01 -0700391 <dd>Only used when providing suggestions for Quick Search Box. This column indicates
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800392whether a search suggestion should be stored as a
Scott Main5e892d82010-05-25 17:04:01 -0700393shortcut and whether it should be validated. Shortcuts are usually formed when the user clicks a
394suggestion from Quick Search Box. If missing, the result is stored as a shortcut and never
395refreshed. If set to {@link android.app.SearchManager#SUGGEST_NEVER_MAKE_SHORTCUT}, the result is
396not stored as a shortcut.
397Otherwise, the shortcut ID is used to check back for an up to date suggestion using
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800398{@link android.app.SearchManager#SUGGEST_URI_PATH_SHORTCUT}.</dd>
399 <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING}</dt>
Scott Main5e892d82010-05-25 17:04:01 -0700400 <dd>Only used when providing suggestions for Quick Search Box. This column specifies that
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800401a spinner should be shown instead of an icon from {@link
402android.app.SearchManager#SUGGEST_COLUMN_ICON_2}
403while the shortcut of this suggestion is being refreshed in Quick Search Box.</dd>
404</dl>
405
Scott Main5e892d82010-05-25 17:04:01 -0700406<p>Some of these columns are discussed more in the following sections.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800407
408
409
Scott Mainabdf0d52011-02-08 10:20:27 -0800410<h2 id="IntentForSuggestions">Declaring an Intent for Suggestions</h2>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800411
Scott Mainabdf0d52011-02-08 10:20:27 -0800412<p>When the user selects a suggestion from the list that appears below the search dialog or widget,
413the system sends a custom {@link android.content.Intent} to your searchable activity. You
414must define the action and data for the intent.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800415
416
Scott Mainabdf0d52011-02-08 10:20:27 -0800417<h3 id="IntentAction">Declaring the intent action</h3>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800418
Scott Mainabdf0d52011-02-08 10:20:27 -0800419<p>The most common intent action for a custom suggestion is {@link
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800420android.content.Intent#ACTION_VIEW}, which is appropriate when
421you want to open something, like the definition for a word, a person's contact information, or a web
Scott Mainabdf0d52011-02-08 10:20:27 -0800422page. However, the intent action can be any other action and can even be different for each
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800423suggestion.</p>
424
Scott Mainabdf0d52011-02-08 10:20:27 -0800425<p>Depending on whether you want all suggestions to use the same intent action, you
Scott Main5e892d82010-05-25 17:04:01 -0700426can define the action in two ways:</p>
427
428<ol type="a">
429 <li>Use the {@code android:searchSuggestIntentAction} attribute of your searchable configuration
430file to define the action for all suggestions. <p>For example:</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800431
432<pre>
433&lt;?xml version="1.0" encoding="utf-8"?>
434&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
435 android:label="@string/app_label"
436 android:hint="@string/search_hint"
Scott Main5e892d82010-05-25 17:04:01 -0700437 android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"
438 <b>android:searchSuggestIntentAction="android.Intent.action.VIEW"</b> >
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800439&lt;/searchable>
440</pre>
441
Scott Main5e892d82010-05-25 17:04:01 -0700442 </li>
443 <li>Use the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column to define the
444action for individual suggestions.
445 <p>Add the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column to
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800446your suggestions table and, for each suggestion, place in it the action to use (such as
Scott Main5e892d82010-05-25 17:04:01 -0700447{@code "android.Intent.action.VIEW"}).</p>
448
449 </li>
450</ol>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800451
452<p>You can also combine these two techniques. For instance, you can include the {@code
453android:searchSuggestIntentAction} attribute with an action to be used with all suggestions by
454default, then override this action for some suggestions by declaring a different action in the
455{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column. If you do not include
456a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column, then the
Scott Mainabdf0d52011-02-08 10:20:27 -0800457intent provided in the {@code android:searchSuggestIntentAction} attribute is used.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800458
459<p class="note"><strong>Note</strong>: If you do not include the
460{@code android:searchSuggestIntentAction} attribute in your searchable configuration, then you
461<em>must</em> include a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION}
Scott Mainabdf0d52011-02-08 10:20:27 -0800462column for every suggestion, or the intent will fail.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800463
464
Scott Main5e892d82010-05-25 17:04:01 -0700465
Scott Mainabdf0d52011-02-08 10:20:27 -0800466<h3 id="IntentData">Declaring intent data</h3>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800467
Scott Mainabdf0d52011-02-08 10:20:27 -0800468<p>When the user selects a suggestion, your searchable activity receives the intent with the
469action you've defined (as discussed in the previous section), but the intent must also carry
470data in order for your activity to identify which suggestion was selected. Specifically,
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800471the data should be something unique for each suggestion, such as the row ID for the suggestion in
Scott Mainabdf0d52011-02-08 10:20:27 -0800472your SQLite table. When the intent is received,
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800473you can retrieve the attached data with {@link android.content.Intent#getData()} or {@link
474android.content.Intent#getDataString()}.</p>
475
Scott Mainabdf0d52011-02-08 10:20:27 -0800476<p>You can define the data included with the intent in two ways:</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800477
478<ol type="a">
479 <li>Define the data for each suggestion inside the {@link
Scott Main5e892d82010-05-25 17:04:01 -0700480android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column of your suggestions table.
481
Scott Mainabdf0d52011-02-08 10:20:27 -0800482<p>Provide all necessary data information for each intent in the suggestions table by including the
Scott Main5e892d82010-05-25 17:04:01 -0700483{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column and then populating it with
Scott Mainabdf0d52011-02-08 10:20:27 -0800484unique data for each row. The data from this column is attached to the intent exactly as you
Scott Main5e892d82010-05-25 17:04:01 -0700485define it in this column. You can then retrieve it with with {@link
486android.content.Intent#getData()} or {@link android.content.Intent#getDataString()}.</p>
487
488<p class="note"><strong>Tip</strong>: It's usually easiest to use the table's row ID as the
489Intent data, because it's always unique. And the easiest way to do that is by using the
490{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column name as an alias for the row ID
491column. See the <a
492href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable Dictionary sample
493app</a> for an example in which {@link android.database.sqlite.SQLiteQueryBuilder} creates a
494projection map of column names to aliases.</p>
495 </li>
496
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800497 <li>Fragment a data URI into two pieces: the portion common to all suggestions and the portion
Scott Mainabdf0d52011-02-08 10:20:27 -0800498unique to each suggestion. Place these parts into the {@code android:searchSuggestintentData}
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800499attribute of the searchable configuration and the {@link
500android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column of your
Scott Main5e892d82010-05-25 17:04:01 -0700501suggestions table, respectively.
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800502
Scott Main5e892d82010-05-25 17:04:01 -0700503<p>Declare the piece of the URI that is common to all suggestions in the {@code
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800504android:searchSuggestIntentData} attribute of your searchable configuration. For example:</p>
505
506<pre>
507&lt;?xml version="1.0" encoding="utf-8"?>
508&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
509 android:label="@string/app_label"
510 android:hint="@string/search_hint"
Scott Main5e892d82010-05-25 17:04:01 -0700511 android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"
Scott Mainabdf0d52011-02-08 10:20:27 -0800512 android:searchSuggestIntentAction="android.intent.action.VIEW"
Scott Main5e892d82010-05-25 17:04:01 -0700513 <b>android:searchSuggestIntentData="content://com.example/datatable"</b> >
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800514&lt;/searchable>
515</pre>
516
Scott Main5e892d82010-05-25 17:04:01 -0700517<p>Then include the final path for each suggestion (the unique part) in the {@link
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800518android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID}
Scott Mainabdf0d52011-02-08 10:20:27 -0800519column of your suggestions table. When the user selects a suggestion, the system takes
Scott Main5e892d82010-05-25 17:04:01 -0700520the string from {@code android:searchSuggestIntentData}, appends a slash ("/") and then adds the
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800521respective value from the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column to
522form a complete content URI. You can then retrieve the {@link android.net.Uri} with with {@link
523android.content.Intent#getData()}.</p>
524
Scott Main5e892d82010-05-25 17:04:01 -0700525 </li>
526</ol>
527
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800528<h4>Add more data</h4>
529
Scott Mainabdf0d52011-02-08 10:20:27 -0800530<p>If you need to express even more information with your intent, you can add another table column,
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800531{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_EXTRA_DATA}, which can store additional
Scott Main5e892d82010-05-25 17:04:01 -0700532information about the suggestion. The data saved in this column is placed in {@link
Scott Mainabdf0d52011-02-08 10:20:27 -0800533android.app.SearchManager#EXTRA_DATA_KEY} of the intent's extra Bundle.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800534
535
Scott Main5e892d82010-05-25 17:04:01 -0700536
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800537<h2 id="HandlingIntent">Handling the Intent</h2>
538
Scott Mainabdf0d52011-02-08 10:20:27 -0800539<p>Now that you provide custom search suggestions with custom intents, you
540need your searchable activity to handle these intents when the user selects a
Scott Main5e892d82010-05-25 17:04:01 -0700541suggestion. This is in addition to handling the {@link
Scott Mainabdf0d52011-02-08 10:20:27 -0800542android.content.Intent#ACTION_SEARCH} intent, which your searchable activity already does.
543Here's an example of how you can handle the intents during your activity {@link
Scott Main5e892d82010-05-25 17:04:01 -0700544android.app.Activity#onCreate(Bundle) onCreate()} callback:</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800545
546<pre>
547Intent intent = getIntent();
548if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
549 // Handle the normal search query case
550 String query = intent.getStringExtra(SearchManager.QUERY);
551 doSearch(query);
552} else if (Intent.ACTION_VIEW.equals(intent.getAction())) {
Scott Main5e892d82010-05-25 17:04:01 -0700553 // Handle a suggestions click (because the suggestions all use ACTION_VIEW)
554 Uri data = intent.getData();
555 showResult(data);
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800556}
557</pre>
558
Scott Mainabdf0d52011-02-08 10:20:27 -0800559<p>In this example, the intent action is {@link
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800560android.content.Intent#ACTION_VIEW} and the data carries a complete URI pointing to the suggested
561item, as synthesized by the {@code android:searchSuggestIntentData} string and {@link
Scott Main5e892d82010-05-25 17:04:01 -0700562android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column. The URI is then passed to the local
563{@code showResult()} method that queries the content provider for the item specified by the URI.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800564
Scott Mainabdf0d52011-02-08 10:20:27 -0800565<p class="note"><strong>Note:</strong> You do <em>not</em> need to add an intent filter to your
566Android manifest file for the intent action you defined with the {@code
Scott Main5e892d82010-05-25 17:04:01 -0700567android:searchSuggestIntentAction} attribute or {@link
Scott Mainabdf0d52011-02-08 10:20:27 -0800568android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column. The system opens your
569searchable activity by name to deliver the suggestion's intent, so the activity does not need to
Scott Main5e892d82010-05-25 17:04:01 -0700570declare the accepted action.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800571
572
573<h2 id="RewritingQueryText">Rewriting the query text</h2>
574
Scott Mainabdf0d52011-02-08 10:20:27 -0800575<p>If the user navigates through the suggestions list using the directional controls (such
576as with a trackball or d-pad), the query text does not update, by default. However, you
577can temporarily rewrite the user's query text as it appears in the text box with
Scott Main5e892d82010-05-25 17:04:01 -0700578a query that matches the suggestion currently in focus. This enables the user to see what query is
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800579being suggested (if appropriate) and then select the search box and edit the query before
580dispatching it as a search.</p>
581
582<p>You can rewrite the query text in the following ways:</p>
583
584<ol type="a">
585 <li>Add the {@code android:searchMode} attribute to your searchable configuration with the
586"queryRewriteFromText" value. In this case, the content from the suggestion's {@link
587android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}
Scott Main5e892d82010-05-25 17:04:01 -0700588column is used to rewrite the query text.</li>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800589 <li>Add the {@code android:searchMode} attribute to your searchable configuration with the
590"queryRewriteFromData" value. In this case, the content from the suggestion's
Scott Main5e892d82010-05-25 17:04:01 -0700591{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column is used to rewrite the
592query text. This should only
593be used with URI's or other data formats that are intended to be user-visible, such as HTTP URLs.
594Internal URI schemes should not be used to rewrite the query in this way.</li>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800595 <li>Provide a unique query text string in the {@link
596android.app.SearchManager#SUGGEST_COLUMN_QUERY} column of your suggestions table. If this column is
Scott Main5e892d82010-05-25 17:04:01 -0700597present and contains a value for the current suggestion, it is used to rewrite the query text
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800598(and override either of the previous implementations).</li>
599</ol>
600
601
Scott Main5e892d82010-05-25 17:04:01 -0700602
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800603<h2 id="QSB">Exposing search suggestions to Quick Search Box</h2>
604
Scott Main5e892d82010-05-25 17:04:01 -0700605<p>Once you configure your application to provide custom search suggestions, making them available
606to the globally accessible Quick Search Box is as easy as modifying your searchable configuration to
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800607include {@code android:includeInGlobalSearch} as "true".</p>
608
Scott Main5e892d82010-05-25 17:04:01 -0700609<p>The only scenario in which additional work is necessary is when your content provider demands a
610read permission. In which case, you need to add a special
611{@code &lt;path-permission&gt;} element for the provider to grant Quick Search Box read access to
612your content provider. For example:</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800613
614<pre>
615&lt;provider android:name="MySuggestionProvider"
Scott Main5e892d82010-05-25 17:04:01 -0700616 android:authorities="com.example.MyCustomSuggestionProvider"
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800617 android:readPermission="com.example.provider.READ_MY_DATA"
Scott Main5e892d82010-05-25 17:04:01 -0700618 android:writePermission="com.example.provider.WRITE_MY_DATA"&gt;
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800619 &lt;path-permission android:pathPrefix="/search_suggest_query"
Scott Main5e892d82010-05-25 17:04:01 -0700620 android:readPermission="android.permission.GLOBAL_SEARCH" /&gt;
621&lt;/provider&gt;
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800622</pre>
623
624<p>In this example, the provider restricts read and write access to the content. The
625{@code &lt;path-permission>} element amends the restriction by granting read access to content
626inside the {@code "/search_suggest_query"} path prefix when the {@code
627"android.permission.GLOBAL_SEARCH"} permission exists. This grants access to Quick Search Box
628so that it may query your content provider for suggestions.</p>
629
Scott Main5e892d82010-05-25 17:04:01 -0700630<p>If your content provider does not enforce read permissions, then Quick Search Box can read
631it by default.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800632
633
634<h3 id="EnablingSuggestions">Enabling suggestions on a device</h3>
635
636<p>When your application is configured to provide suggestions in Quick Search Box, it is not
637actually enabled to provide suggestions in Quick Search Box, by default. It is the user's choice
638whether to include suggestions from your application in the Quick Search Box. To enable search
639suggestions from your application, the user must open "Searchable items" (in Settings > Search) and
640enable your application as a searchable item.</p>
641
642<p>Each application that is available to Quick Search Box has an entry in the Searchable items
643settings page. The entry includes the name of the application and a short description of what
644content can be searched from the application and made available for suggestions in Quick Search Box.
645To define the description text for your searchable application, add the {@code
646android:searchSettingsDescription} attribute to your searchable configuration. For example:</p>
647
648<pre>
649&lt;?xml version="1.0" encoding="utf-8"?>
650&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
651 android:label="@string/app_label"
652 android:hint="@string/search_hint"
Scott Main5e892d82010-05-25 17:04:01 -0700653 android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"
Scott Mainabdf0d52011-02-08 10:20:27 -0800654 android:searchSuggestIntentAction="android.intent.action.VIEW"
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800655 android:includeInGlobalSearch="true"
Scott Main5e892d82010-05-25 17:04:01 -0700656 <b>android:searchSettingsDescription="@string/search_description"</b> >
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800657&lt;/searchable>
658</pre>
659
660<p>The string for {@code android:searchSettingsDescription} should be as concise as possible and
661state the content that is searchable. For example, "Artists, albums, and tracks" for a music
662application, or "Saved notes" for a notepad application. Providing this description is important so
Scott Main5e892d82010-05-25 17:04:01 -0700663the user knows what kind of suggestions are provided. You should always include this attribute
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800664when {@code android:includeInGlobalSearch} is "true".</p>
665
Scott Main5e892d82010-05-25 17:04:01 -0700666<p>Remember that the user must visit the settings menu to enable search suggestions for your
667application before your search suggestions appear in Quick Search Box. As such, if search is an
668important aspect of your application, then you might want to consider a way to convey that to
669your users &mdash; you might provide a note the first time they launch the app that instructs
670them how to enable search suggestions for Quick Search Box.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800671
672
673<h3 id="ManagingShortcuts">Managing Quick Search Box suggestion shortcuts</h3>
674
Scott Main5e892d82010-05-25 17:04:01 -0700675<p>Suggestions that the user selects from Quick Search Box can be automatically made into shortcuts.
Scott Mainabdf0d52011-02-08 10:20:27 -0800676These are suggestions that the system has copied from your content provider so it can
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800677quickly access the suggestion without the need to re-query your content provider. </p>
678
679<p>By default, this is enabled for all suggestions retrieved by Quick Search Box, but if your
Scott Main5e892d82010-05-25 17:04:01 -0700680suggestion data changes over time, then you can request that the shortcuts be refreshed. For
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800681instance, if your suggestions refer to dynamic data, such as a contact's presence status, then you
682should request that the suggestion shortcuts be refreshed when shown to the user. To do so,
683include the {@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} in your suggestions table.
684Using this column, you can
Scott Main5e892d82010-05-25 17:04:01 -0700685configure the shortcut behavior for each suggestion in one of the following ways:</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800686
687<ol type="a">
Scott Main5e892d82010-05-25 17:04:01 -0700688 <li>Have Quick Search Box re-query your content provider for a fresh version of the suggestion
689shortcut.
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800690 <p>Provide a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} column
Scott Main5e892d82010-05-25 17:04:01 -0700691and the suggestion is
692re-queried for a fresh version each time the shortcut is displayed. The shortcut
693is quickly displayed with whatever data was most recently available until the refresh query
694returns, at which point the suggestion is refreshed with the new information. The
695refresh query is sent to your content provider with a URI path of {@link
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800696android.app.SearchManager#SUGGEST_URI_PATH_SHORTCUT}
Scott Main5e892d82010-05-25 17:04:01 -0700697(instead of {@link android.app.SearchManager#SUGGEST_URI_PATH_QUERY}).</p>
698 <p>The {@link android.database.Cursor} you return should contain one suggestion using the
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800699same columns as the original suggestion, or be empty, indicating that the shortcut is no
Scott Main5e892d82010-05-25 17:04:01 -0700700longer valid (in which case, the suggestion disappears and the shortcut is removed).</p>
701 <p>If a suggestion refers to data that could take longer to refresh, such as a network-based
702refresh, you can also add the {@link
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800703android.app.SearchManager#SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING} column to your suggestions
704table with a value
705of "true" in order to show a progress spinner for the right hand icon until the refresh is complete.
Scott Main5e892d82010-05-25 17:04:01 -0700706Any value other than "true" does not show the progress spinner.</p>
707 </li>
708
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800709 <li>Prevent the suggestion from being copied into a shortcut at all.
710 <p>Provide a value of {@link android.app.SearchManager#SUGGEST_NEVER_MAKE_SHORTCUT} in the
711{@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} column. In
Scott Main5e892d82010-05-25 17:04:01 -0700712this case, the suggestion is never copied into a shortcut. This should only be necessary if you
713absolutely do not want the previously copied suggestion to appear. (Recall that if you
714provide a normal value for the column, then the suggestion shortcut appears only until the
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800715refresh query returns.)</p></li>
716 <li>Allow the default shortcut behavior to apply.
Scott Main5e892d82010-05-25 17:04:01 -0700717 <p>Leave the {@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} empty for each
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800718suggestion that will not change and can be saved as a shortcut.</p></li>
719</ol>
720
Scott Main5e892d82010-05-25 17:04:01 -0700721<p>If none of your suggestions ever change, then you do not need the
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800722{@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} column at all.</p>
723
Scott Main5e892d82010-05-25 17:04:01 -0700724<p class="note"><strong>Note</strong>: Quick Search Box ultimately decides whether or not to create
725a shortcut for a suggestion, considering these values as a strong request from your
726application&mdash;there is no guarantee that the behavior you have requested for your suggestion
727shortcuts will be honored.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800728
729
730<h3 id="AboutRanking">About Quick Search Box suggestion ranking</h3>
731
Scott Main5e892d82010-05-25 17:04:01 -0700732<p>Once you make your application's search suggestions available to Quick Search Box, the Quick
733Search Box ranking determines how the suggestions are surfaced to the user for a particular query.
734This might depend on how many other apps have results for that query, and how often the user has
735selected your results compared to those from other apps. There is no guarantee about how your
736suggestions are ranked, or whether your app's suggestions show at all for a given query. In
737general, you can expect that providing quality results increases the likelihood that your app's
738suggestions are provided in a prominent position and apps that provide low quality suggestions
739are more likely to be ranked lower or not displayed.</p>
Scott Mainb3b2b4f2010-02-12 17:19:02 -0800740
741<div class="special">
742<p>See the <a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable
743Dictionary sample app</a> for a complete demonstration of custom search suggestions.</p>
744</div>
745