Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 1 | page.title=Adding Custom Suggestions |
Joe Fernandez | 33baa5a | 2013-11-14 11:41:19 -0800 | [diff] [blame] | 2 | page.tags=SearchRecentSuggestionsProvider, |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 3 | @jd:body |
| 4 | |
| 5 | <div id="qv-wrapper"> |
| 6 | <div id="qv"> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 7 | <h2>In this document</h2> |
| 8 | <ol> |
| 9 | <li><a href="#TheBasics">The Basics</a></li> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 10 | <li><a href="#CustomSearchableConfiguration">Modifying the Searchable Configuration</a></li> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 11 | <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 Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 17 | <li><a href="#IntentForSuggestions">Declaring an Intent for Suggestions</a> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 18 | <ol> |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 19 | <li><a href="#IntentAction">Declaring the intent action</a></li> |
| 20 | <li><a href="#IntentData">Declaring the intent data</a></li> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 21 | </ol> |
| 22 | </li> |
| 23 | <li><a href="#HandlingIntent">Handling the Intent</a></li> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 24 | <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 Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 26 | </ol> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 27 | |
| 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 Main | ec80d7f | 2010-09-24 16:17:27 -0700 | [diff] [blame] | 35 | <h2>Related samples</h2> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 36 | <ol> |
| 37 | <li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable |
| 38 | Dictionary</a></li> |
| 39 | </ol> |
| 40 | |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 41 | <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 Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 45 | </ol> |
| 46 | </div> |
| 47 | </div> |
| 48 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 49 | <p>When using the Android search dialog or search widget, you can provide custom search suggestions |
| 50 | that are created from data in your application. For example, if your application is a word |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 51 | dictionary, you can suggest words from the |
| 52 | dictionary that match the text entered so far. These are the most valuable suggestions, because you |
| 53 | can effectively predict what the user wants and provide instant access to it. Figure 1 shows |
| 54 | an example of a search dialog with custom suggestions.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 55 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 56 | <p>Once you provide custom suggestions, you can also make them available to the system-wide Quick |
| 57 | Search 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 Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 60 | Android search dialog or a search widget for searches in your |
| 61 | application. If you haven't, see <a href="search-dialog.html">Creating a Search Interface</a>.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 62 | |
| 63 | |
| 64 | <h2 id="TheBasics">The Basics</h2> |
| 65 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 66 | <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 |
| 69 | search suggestions.</p> |
| 70 | </div> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 71 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 72 | <p>When the user selects a custom suggestion, the Android system sends an {@link |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 73 | android.content.Intent} to |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 74 | your searchable activity. Whereas a normal search query sends an intent with the {@link |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 75 | android.content.Intent#ACTION_SEARCH} action, you can instead define your custom suggestions to use |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 76 | {@link android.content.Intent#ACTION_VIEW} (or any other intent action), and also include data |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 77 | that's relevant to the selected suggestion. Continuing |
| 78 | the dictionary example, when the user selects a suggestion, your application can immediately |
| 79 | open the definition for that word, instead of searching the dictionary for matches.</p> |
| 80 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 81 | <p>To provide custom suggestions, do the following:</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 82 | |
| 83 | <ul> |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 84 | <li>Implement a basic searchable activity, as described in <a |
| 85 | href="search-dialog.html">Creating a Search Interface</a>.</li> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 86 | <li>Modify the searchable configuration with information about the content provider that |
| 87 | provides custom suggestions.</li> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 88 | <li>Build a table (such as in an {@link android.database.sqlite.SQLiteDatabase}) for your |
| 89 | suggestions and format the table with required columns.</li> |
| 90 | <li>Create a <a href="{@docRoot}guide/topics/providers/content-providers.html">Content |
| 91 | Provider</a> that has access to your suggestions table and declare the provider |
| 92 | in your manifest.</li> |
| 93 | <li>Declare the type of {@link android.content.Intent} to be sent when the user selects a |
| 94 | suggestion (including a custom action and custom data). </li> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 95 | </ul> |
| 96 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 97 | <p>Just as the Android system displays the search dialog, it also displays your search |
| 98 | suggestions. All you need is a content provider from which the system can retrieve your |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 99 | suggestions. If you're not familiar with creating content |
| 100 | providers, read the <a href="{@docRoot}guide/topics/providers/content-providers.html">Content |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 101 | Providers</a> developer guide before you continue.</p> |
| 102 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 103 | <p>When the system identifies that your activity is searchable and provides search |
| 104 | suggestions, the following procedure takes place when the user types a query:</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 105 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 106 | <ol> |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 107 | <li>The system takes the search query text (whatever has been typed so far) and performs a |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 108 | query 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 Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 110 | suggestions that are relevant to the search query text.</li> |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 111 | <li>The system displays the list of suggestions provided by the Cursor.</li> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 112 | </ol> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 113 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 114 | <p>Once the custom suggestions are displayed, the following might happen:</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 115 | |
| 116 | <ul> |
| 117 | <li>If the user types another key, or changes the query in any way, the above steps are repeated |
| 118 | and the suggestion list is updated as appropriate. </li> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 119 | <li>If the user executes the search, the suggestions are ignored and the search is delivered |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 120 | to your searchable activity using the normal {@link android.content.Intent#ACTION_SEARCH} |
| 121 | intent.</li> |
| 122 | <li>If the user selects a suggestion, an intent is sent to your searchable activity, carrying a |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 123 | custom 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 |
| 131 | to the {@code <searchable>} element in your searchable configuration file. For example:</p> |
| 132 | |
| 133 | <pre> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 134 | <?xml version="1.0" encoding="utf-8"?> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 135 | <searchable xmlns:android="http://schemas.android.com/apk/res/android" |
| 136 | android:label="@string/app_label" |
| 137 | android:hint="@string/search_hint" |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 138 | <b>android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"</b>> |
| 139 | </searchable> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 140 | </pre> |
| 141 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 142 | <p>You might need some additional attributes, depending on the type of intent you attach |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 143 | to each suggestion and how you want to format queries to your content provider. The other optional |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 144 | attributes are discussed in the following sections.</p> |
| 145 | |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 146 | |
| 147 | |
| 148 | <h2 id="CustomContentProvider">Creating a Content Provider</h2> |
| 149 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 150 | <p>Creating a content provider for custom suggestions requires previous knowledge about content |
| 151 | providers that's covered in the <a |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 152 | href="{@docRoot}guide/topics/providers/content-providers.html">Content Provider</a> developer |
| 153 | guide. For the most part, a content provider for custom suggestions is the |
| 154 | same as any other content provider. However, for each suggestion you provide, the respective row in |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 155 | the {@link android.database.Cursor} must include specific columns that the system |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 156 | understands and uses to format the suggestions.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 157 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 158 | <p>When the user starts typing into the search dialog or search widget, the system queries |
| 159 | your content provider for suggestions by calling {@link |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 160 | android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} each time |
| 161 | a letter is typed. In your implementation of {@link |
| 162 | android.content.ContentProvider#query(Uri,String[],String,String[],String) query()}, your |
| 163 | content provider must search your suggestion data and return a {@link |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 164 | android.database.Cursor} that points to the rows you have determined to be good suggestions.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 165 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 166 | <p>Details about creating a content provider for custom suggestions are discussed in the following |
| 167 | two sections:</p> |
| 168 | <dl> |
| 169 | <dt><a href="#HandlingSuggestionQuery">Handling the suggestion query</a></dt> |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 170 | <dd>How the system sends requests to your content provider and how to handle them</dd> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 171 | <dt><a href="#SuggestionTable">Building a suggestion table</a></dt> |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 172 | <dd>How to define the columns that the system expects in the {@link |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 173 | android.database.Cursor} returned with each query</dd> |
| 174 | </dl> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 175 | |
| 176 | |
| 177 | <h3 id="HandlingSuggestionQuery">Handling the suggestion query</h3> |
| 178 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 179 | <p>When the system requests suggestions from your content provider, it calls your content |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 180 | provider's {@link android.content.ContentProvider#query(Uri,String[],String,String[],String) |
| 181 | query()} method. You must |
| 182 | implement this method to search your suggestion data and return a |
| 183 | {@link android.database.Cursor} pointing to the suggestions you deem relevant.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 184 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 185 | <p>Here's a summary of the parameters that the system passes to your {@link |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 186 | android.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 Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 191 | <dd>Always a content {@link android.net.Uri}, formatted as: |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 192 | <pre class="no-pretty-print"> |
| 193 | content://<em>your.authority</em>/<em>optional.suggest.path</em>/<em>{@link |
| 194 | android.app.SearchManager#SUGGEST_URI_PATH_QUERY}</em> |
| 195 | </pre> |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 196 | <p>The default behavior is for system to pass this URI and append it with the query text. |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 197 | For example:</p> |
| 198 | <pre class="no-pretty-print"> |
| 199 | content://<em>your.authority</em>/<em>optional.suggest.path</em>/<em>{@link |
| 200 | android.app.SearchManager#SUGGEST_URI_PATH_QUERY}</em>/puppies |
| 201 | </pre> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 202 | <p>The query text on the end is encoded using URI encoding rules, so you might need to decode |
| 203 | it before performing a search.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 204 | <p>The <em>{@code optional.suggest.path}</em> portion is only included in the URI if you have set |
| 205 | such a path in your searchable configuration file with the {@code android:searchSuggestPath} |
| 206 | attribute. This is only needed if you use the same content provider for multiple searchable |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 207 | activities, in which case, you need to disambiguate the source of the suggestion query.</p> |
| 208 | <p class="note"><strong>Note:</strong> {@link |
| 209 | android.app.SearchManager#SUGGEST_URI_PATH_QUERY} is not the literal |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 210 | string provided in the URI, but a constant that you should use if you need to refer to this |
| 211 | path.</p> |
| 212 | </dd> |
| 213 | |
| 214 | <dt><code>projection</code></dt> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 215 | <dd>Always null</dd> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 216 | |
| 217 | <dt><code>selection</code></dt> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 218 | <dd>The value provided in the {@code android:searchSuggestSelection} attribute of |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 219 | your searchable configuration file, or null if you have not declared the {@code |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 220 | android:searchSuggestSelection} attribute. More about using this to <a href="#GetTheQuery">get the |
| 221 | query</a> below.</dd> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 222 | |
| 223 | <dt><code>selectionArgs</code></dt> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 224 | <dd>Contains the search query as the first (and only) element of the array if you have |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 225 | declared the {@code android:searchSuggestSelection} attribute in your searchable configuration. If |
| 226 | you have not declared {@code android:searchSuggestSelection}, then this parameter is null. More |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 227 | about using this to <a href="#GetTheQuery">get the query</a> below.</dd> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 228 | |
| 229 | <dt><code>sortOrder</code></dt> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 230 | <dd>Always null</dd> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 231 | </dl> |
| 232 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 233 | <p>The system can send you the search query text in two ways. The |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 234 | default manner is for the query text to be included as the last path of the content |
| 235 | URI passed in the {@code uri} parameter. However, if you include a selection value in your |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 236 | searchable configuration's {@code |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 237 | android:searchSuggestSelection} attribute, then the query text is instead passed as the first |
| 238 | element of the {@code selectionArgs} string array. Both options are summarized next.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 239 | |
| 240 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 241 | <h4 id="GetTheQueryUri">Get the query in the Uri</h4> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 242 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 243 | <p>By default, the query is appended as the last segment of the {@code uri} |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 244 | parameter (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> |
| 248 | String query = uri.getLastPathSegment().toLowerCase(); |
| 249 | </pre> |
| 250 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 251 | <p>This returns the last segment of the {@link android.net.Uri}, which is the query text entered |
| 252 | by the user.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 253 | |
| 254 | |
| 255 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 256 | <h4 id="GetTheQuery">Get the query in the selection arguments</h4> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 257 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 258 | <p>Instead of using the URI, you might decide it makes more sense for your {@link |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 259 | android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method to |
| 260 | receive everything it needs to perform the look-up and you want the |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 261 | {@code selection} and {@code selectionArgs} parameters to carry the appropriate values. In such a |
| 262 | case, add the {@code android:searchSuggestSelection} attribute to your searchable configuration with |
| 263 | your SQLite selection string. In the selection string, include a question mark ("?") as |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 264 | a placeholder for the actual search query. The system calls {@link |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 265 | android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} with the |
| 266 | selection string as the {@code selection} parameter and the search query as the first |
| 267 | element in the {@code selectionArgs} array.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 268 | |
| 269 | <p>For example, here's how you might form the {@code android:searchSuggestSelection} attribute to |
| 270 | create a full-text search statement:</p> |
| 271 | |
| 272 | <pre> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 273 | <?xml version="1.0" encoding="utf-8"?> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 274 | <searchable xmlns:android="http://schemas.android.com/apk/res/android" |
| 275 | android:label="@string/app_label" |
| 276 | android:hint="@string/search_hint" |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 277 | android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider" |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 278 | android:searchSuggestIntentAction="android.intent.action.VIEW" |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 279 | <b>android:searchSuggestSelection="word MATCH ?"</b>> |
| 280 | </searchable> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 281 | </pre> |
| 282 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 283 | <p>With this configuration, your {@link |
| 284 | android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 285 | delivers the {@code selection} parameter as {@code "word MATCH ?"} and the {@code selectionArgs} |
| 286 | parameter as the search query. When you pass these to an SQLite |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 287 | {@link android.database.sqlite.SQLiteDatabase#query(String,String[],String,String[],String,String, |
| 288 | String) query()} method, as their respective arguments, they are synthesized together (the |
| 289 | question mark is replaced with the query |
| 290 | text). If you chose to receive suggestion queries this way and need to add wildcards to |
| 291 | the query text, append (and/or prefix) them to the {@code selectionArgs} |
| 292 | parameter, because this value is wrapped in quotes and inserted in place of the |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 293 | question mark.</p> |
| 294 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 295 | <p>Another new attribute in the example above is {@code android:searchSuggestIntentAction}, which |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 296 | defines the intent action sent with each intent when the user selects a suggestion. It is |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 297 | discussed further in the section about <a href="#IntentForSuggestions">Declaring an Intent for |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 298 | Suggestions</a>.</p> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 299 | |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 300 | <p class="note"><strong>Tip:</strong> If you don't want to define a selection clause in |
| 301 | the {@code android:searchSuggestSelection} attribute, but would still like to receive the query |
| 302 | text in the {@code selectionArgs} parameter, simply provide a non-null value for the {@code |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 303 | android:searchSuggestSelection} attribute. This triggers the query to be passed in {@code |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 304 | selectionArgs} and you can ignore the {@code selection} parameter. In this way, you can instead |
| 305 | define the actual selection clause at a lower level so that your content provider doesn't have to |
| 306 | handle 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 Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 314 | <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 |
| 316 | columns required by the |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 317 | system, then you can search your suggestion data for matches and then format them |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 318 | into the necessary table on each request. To do so, create a {@link android.database.MatrixCursor} |
| 319 | using the required column names and then add a row for each suggestion using {@link |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 320 | android.database.MatrixCursor#addRow(Object[])}. Return the final product from your Content |
| 321 | Provider's {@link |
| 322 | android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method.</p> |
| 323 | </div> |
| 324 | </div> |
| 325 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 326 | <p>When you return suggestions to the system with a {@link android.database.Cursor}, the |
| 327 | system expects specific columns in each row. So, regardless of whether you |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 328 | decide to store |
| 329 | your suggestion data in an SQLite database on the device, a database on a web server, or another |
| 330 | format on the device or web, you must format the suggestions as rows in a table and |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 331 | present them with a {@link android.database.Cursor}. The system understands several columns, but |
| 332 | only two are required:</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 333 | |
| 334 | <dl> |
| 335 | <dt>{@link android.provider.BaseColumns#_ID}</dt> |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 336 | <dd>A unique integer row ID for each suggestion. The system requires this in order |
| 337 | to present suggestions in a {@link android.widget.ListView}.</dd> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 338 | <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}</dt> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 339 | <dd>The string that is presented as a suggestion.</dd> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 340 | </dl> |
| 341 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 342 | <p>The following columns are all optional (and most are discussed further in the following |
| 343 | sections):</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 344 | |
| 345 | <dl> |
| 346 | <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_2}</dt> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 347 | <dd>A string. If your Cursor includes this column, then all suggestions are provided in a |
| 348 | two-line format. The string in this column is displayed as a second, smaller line of text below the |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 349 | primary 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 Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 351 | <dd>A drawable resource, content, or file URI string. If your Cursor includes this column, then |
| 352 | all suggestions are provided in an icon-plus-text format with the drawable icon on the left side. |
| 353 | This can be null or zero to indicate no icon in this row.</dd> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 354 | <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_ICON_2}</dt> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 355 | <dd>A drawable resource, content, or file URI string. If your Cursor includes this column, then |
| 356 | all suggestions are provided in an icon-plus-text format with the icon on the right side. This can |
| 357 | be null or zero to indicate no icon in this row.</dd> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 358 | <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION}</dt> |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 359 | <dd>An intent action string. If this column exists and contains a value at the given row, the |
| 360 | action defined here is used when forming the suggestion's intent. If the element is not |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 361 | provided, the action is taken from the {@code android:searchSuggestIntentAction} field in your |
| 362 | searchable configuration. If your action is the same for all |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 363 | suggestions, it is more efficient to specify the action using {@code |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 364 | android:searchSuggestIntentAction} and omit this column.</dd> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 365 | <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA}</dt> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 366 | <dd>A data URI string. If this column exists and contains a value at the given row, this is the |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 367 | data that is used when forming the suggestion's intent. If the element is not provided, the data is |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 368 | taken from the {@code android:searchSuggestIntentData} field in your searchable configuration. If |
| 369 | neither source is provided, |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 370 | the intent's data field is null. If your data is the same for all suggestions, or can be |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 371 | described using a constant part and a specific ID, it is more efficient to specify it using {@code |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 372 | android:searchSuggestIntentData} and omit this column. |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 373 | </dd> |
| 374 | <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID}</dt> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 375 | <dd>A URI path string. If this column exists and contains a value at the given row, then "/" and |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 376 | this value is appended to the data field in the intent. This should only be used if the data field |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 377 | specified |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 378 | by the {@code android:searchSuggestIntentData} attribute in the searchable configuration has already |
| 379 | been set to an appropriate base string.</dd> |
| 380 | <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_EXTRA_DATA}</dt> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 381 | <dd>Arbitrary data. If this column exists and contains a value at a given row, this is the |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 382 | <em>extra</em> data used when forming the suggestion's intent. If not provided, the |
| 383 | intent's extra data field is null. This column allows suggestions to provide additional data that is |
| 384 | included as an extra in the intent's {@link android.app.SearchManager#EXTRA_DATA_KEY} key.</dd> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 385 | <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_QUERY}</dt> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 386 | <dd>If this column exists and this element exists at the given row, this is the data that is |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 387 | used when forming the suggestion's query, included as an extra in the intent's {@link |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 388 | android.app.SearchManager#QUERY} key. Required if suggestion's action is {@link |
| 389 | android.content.Intent#ACTION_SEARCH}, optional otherwise.</dd> |
| 390 | <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID}</dt> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 391 | <dd>Only used when providing suggestions for Quick Search Box. This column indicates |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 392 | whether a search suggestion should be stored as a |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 393 | shortcut and whether it should be validated. Shortcuts are usually formed when the user clicks a |
| 394 | suggestion from Quick Search Box. If missing, the result is stored as a shortcut and never |
| 395 | refreshed. If set to {@link android.app.SearchManager#SUGGEST_NEVER_MAKE_SHORTCUT}, the result is |
| 396 | not stored as a shortcut. |
| 397 | Otherwise, the shortcut ID is used to check back for an up to date suggestion using |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 398 | {@link android.app.SearchManager#SUGGEST_URI_PATH_SHORTCUT}.</dd> |
| 399 | <dt>{@link android.app.SearchManager#SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING}</dt> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 400 | <dd>Only used when providing suggestions for Quick Search Box. This column specifies that |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 401 | a spinner should be shown instead of an icon from {@link |
| 402 | android.app.SearchManager#SUGGEST_COLUMN_ICON_2} |
| 403 | while the shortcut of this suggestion is being refreshed in Quick Search Box.</dd> |
| 404 | </dl> |
| 405 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 406 | <p>Some of these columns are discussed more in the following sections.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 407 | |
| 408 | |
| 409 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 410 | <h2 id="IntentForSuggestions">Declaring an Intent for Suggestions</h2> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 411 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 412 | <p>When the user selects a suggestion from the list that appears below the search dialog or widget, |
| 413 | the system sends a custom {@link android.content.Intent} to your searchable activity. You |
| 414 | must define the action and data for the intent.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 415 | |
| 416 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 417 | <h3 id="IntentAction">Declaring the intent action</h3> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 418 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 419 | <p>The most common intent action for a custom suggestion is {@link |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 420 | android.content.Intent#ACTION_VIEW}, which is appropriate when |
| 421 | you want to open something, like the definition for a word, a person's contact information, or a web |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 422 | page. However, the intent action can be any other action and can even be different for each |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 423 | suggestion.</p> |
| 424 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 425 | <p>Depending on whether you want all suggestions to use the same intent action, you |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 426 | can define the action in two ways:</p> |
| 427 | |
| 428 | <ol type="a"> |
| 429 | <li>Use the {@code android:searchSuggestIntentAction} attribute of your searchable configuration |
| 430 | file to define the action for all suggestions. <p>For example:</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 431 | |
| 432 | <pre> |
| 433 | <?xml version="1.0" encoding="utf-8"?> |
| 434 | <searchable xmlns:android="http://schemas.android.com/apk/res/android" |
| 435 | android:label="@string/app_label" |
| 436 | android:hint="@string/search_hint" |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 437 | android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider" |
| 438 | <b>android:searchSuggestIntentAction="android.Intent.action.VIEW"</b> > |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 439 | </searchable> |
| 440 | </pre> |
| 441 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 442 | </li> |
| 443 | <li>Use the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column to define the |
| 444 | action for individual suggestions. |
| 445 | <p>Add the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column to |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 446 | your suggestions table and, for each suggestion, place in it the action to use (such as |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 447 | {@code "android.Intent.action.VIEW"}).</p> |
| 448 | |
| 449 | </li> |
| 450 | </ol> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 451 | |
| 452 | <p>You can also combine these two techniques. For instance, you can include the {@code |
| 453 | android:searchSuggestIntentAction} attribute with an action to be used with all suggestions by |
| 454 | default, 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 |
| 456 | a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column, then the |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 457 | intent provided in the {@code android:searchSuggestIntentAction} attribute is used.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 458 | |
| 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 Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 462 | column for every suggestion, or the intent will fail.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 463 | |
| 464 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 465 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 466 | <h3 id="IntentData">Declaring intent data</h3> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 467 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 468 | <p>When the user selects a suggestion, your searchable activity receives the intent with the |
| 469 | action you've defined (as discussed in the previous section), but the intent must also carry |
| 470 | data in order for your activity to identify which suggestion was selected. Specifically, |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 471 | the data should be something unique for each suggestion, such as the row ID for the suggestion in |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 472 | your SQLite table. When the intent is received, |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 473 | you can retrieve the attached data with {@link android.content.Intent#getData()} or {@link |
| 474 | android.content.Intent#getDataString()}.</p> |
| 475 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 476 | <p>You can define the data included with the intent in two ways:</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 477 | |
| 478 | <ol type="a"> |
| 479 | <li>Define the data for each suggestion inside the {@link |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 480 | android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column of your suggestions table. |
| 481 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 482 | <p>Provide all necessary data information for each intent in the suggestions table by including the |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 483 | {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column and then populating it with |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 484 | unique data for each row. The data from this column is attached to the intent exactly as you |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 485 | define it in this column. You can then retrieve it with with {@link |
| 486 | android.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 |
| 489 | Intent 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 |
| 491 | column. See the <a |
| 492 | href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable Dictionary sample |
| 493 | app</a> for an example in which {@link android.database.sqlite.SQLiteQueryBuilder} creates a |
| 494 | projection map of column names to aliases.</p> |
| 495 | </li> |
| 496 | |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 497 | <li>Fragment a data URI into two pieces: the portion common to all suggestions and the portion |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 498 | unique to each suggestion. Place these parts into the {@code android:searchSuggestintentData} |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 499 | attribute of the searchable configuration and the {@link |
| 500 | android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column of your |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 501 | suggestions table, respectively. |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 502 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 503 | <p>Declare the piece of the URI that is common to all suggestions in the {@code |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 504 | android:searchSuggestIntentData} attribute of your searchable configuration. For example:</p> |
| 505 | |
| 506 | <pre> |
| 507 | <?xml version="1.0" encoding="utf-8"?> |
| 508 | <searchable xmlns:android="http://schemas.android.com/apk/res/android" |
| 509 | android:label="@string/app_label" |
| 510 | android:hint="@string/search_hint" |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 511 | android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider" |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 512 | android:searchSuggestIntentAction="android.intent.action.VIEW" |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 513 | <b>android:searchSuggestIntentData="content://com.example/datatable"</b> > |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 514 | </searchable> |
| 515 | </pre> |
| 516 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 517 | <p>Then include the final path for each suggestion (the unique part) in the {@link |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 518 | android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 519 | column of your suggestions table. When the user selects a suggestion, the system takes |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 520 | the string from {@code android:searchSuggestIntentData}, appends a slash ("/") and then adds the |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 521 | respective value from the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column to |
| 522 | form a complete content URI. You can then retrieve the {@link android.net.Uri} with with {@link |
| 523 | android.content.Intent#getData()}.</p> |
| 524 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 525 | </li> |
| 526 | </ol> |
| 527 | |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 528 | <h4>Add more data</h4> |
| 529 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 530 | <p>If you need to express even more information with your intent, you can add another table column, |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 531 | {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_EXTRA_DATA}, which can store additional |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 532 | information about the suggestion. The data saved in this column is placed in {@link |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 533 | android.app.SearchManager#EXTRA_DATA_KEY} of the intent's extra Bundle.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 534 | |
| 535 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 536 | |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 537 | <h2 id="HandlingIntent">Handling the Intent</h2> |
| 538 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 539 | <p>Now that you provide custom search suggestions with custom intents, you |
| 540 | need your searchable activity to handle these intents when the user selects a |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 541 | suggestion. This is in addition to handling the {@link |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 542 | android.content.Intent#ACTION_SEARCH} intent, which your searchable activity already does. |
| 543 | Here's an example of how you can handle the intents during your activity {@link |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 544 | android.app.Activity#onCreate(Bundle) onCreate()} callback:</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 545 | |
| 546 | <pre> |
| 547 | Intent intent = getIntent(); |
| 548 | if (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 Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 553 | // Handle a suggestions click (because the suggestions all use ACTION_VIEW) |
| 554 | Uri data = intent.getData(); |
| 555 | showResult(data); |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 556 | } |
| 557 | </pre> |
| 558 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 559 | <p>In this example, the intent action is {@link |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 560 | android.content.Intent#ACTION_VIEW} and the data carries a complete URI pointing to the suggested |
| 561 | item, as synthesized by the {@code android:searchSuggestIntentData} string and {@link |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 562 | android.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 Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 564 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 565 | <p class="note"><strong>Note:</strong> You do <em>not</em> need to add an intent filter to your |
| 566 | Android manifest file for the intent action you defined with the {@code |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 567 | android:searchSuggestIntentAction} attribute or {@link |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 568 | android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column. The system opens your |
| 569 | searchable activity by name to deliver the suggestion's intent, so the activity does not need to |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 570 | declare the accepted action.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 571 | |
| 572 | |
| 573 | <h2 id="RewritingQueryText">Rewriting the query text</h2> |
| 574 | |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 575 | <p>If the user navigates through the suggestions list using the directional controls (such |
| 576 | as with a trackball or d-pad), the query text does not update, by default. However, you |
| 577 | can temporarily rewrite the user's query text as it appears in the text box with |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 578 | a query that matches the suggestion currently in focus. This enables the user to see what query is |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 579 | being suggested (if appropriate) and then select the search box and edit the query before |
| 580 | dispatching 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 |
| 587 | android.app.SearchManager#SUGGEST_COLUMN_TEXT_1} |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 588 | column is used to rewrite the query text.</li> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 589 | <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 Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 591 | {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column is used to rewrite the |
| 592 | query text. This should only |
| 593 | be used with URI's or other data formats that are intended to be user-visible, such as HTTP URLs. |
| 594 | Internal URI schemes should not be used to rewrite the query in this way.</li> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 595 | <li>Provide a unique query text string in the {@link |
| 596 | android.app.SearchManager#SUGGEST_COLUMN_QUERY} column of your suggestions table. If this column is |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 597 | present and contains a value for the current suggestion, it is used to rewrite the query text |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 598 | (and override either of the previous implementations).</li> |
| 599 | </ol> |
| 600 | |
| 601 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 602 | |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 603 | <h2 id="QSB">Exposing search suggestions to Quick Search Box</h2> |
| 604 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 605 | <p>Once you configure your application to provide custom search suggestions, making them available |
| 606 | to the globally accessible Quick Search Box is as easy as modifying your searchable configuration to |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 607 | include {@code android:includeInGlobalSearch} as "true".</p> |
| 608 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 609 | <p>The only scenario in which additional work is necessary is when your content provider demands a |
| 610 | read permission. In which case, you need to add a special |
| 611 | {@code <path-permission>} element for the provider to grant Quick Search Box read access to |
| 612 | your content provider. For example:</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 613 | |
| 614 | <pre> |
| 615 | <provider android:name="MySuggestionProvider" |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 616 | android:authorities="com.example.MyCustomSuggestionProvider" |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 617 | android:readPermission="com.example.provider.READ_MY_DATA" |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 618 | android:writePermission="com.example.provider.WRITE_MY_DATA"> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 619 | <path-permission android:pathPrefix="/search_suggest_query" |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 620 | android:readPermission="android.permission.GLOBAL_SEARCH" /> |
| 621 | </provider> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 622 | </pre> |
| 623 | |
| 624 | <p>In this example, the provider restricts read and write access to the content. The |
| 625 | {@code <path-permission>} element amends the restriction by granting read access to content |
| 626 | inside the {@code "/search_suggest_query"} path prefix when the {@code |
| 627 | "android.permission.GLOBAL_SEARCH"} permission exists. This grants access to Quick Search Box |
| 628 | so that it may query your content provider for suggestions.</p> |
| 629 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 630 | <p>If your content provider does not enforce read permissions, then Quick Search Box can read |
| 631 | it by default.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 632 | |
| 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 |
| 637 | actually enabled to provide suggestions in Quick Search Box, by default. It is the user's choice |
| 638 | whether to include suggestions from your application in the Quick Search Box. To enable search |
| 639 | suggestions from your application, the user must open "Searchable items" (in Settings > Search) and |
| 640 | enable 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 |
| 643 | settings page. The entry includes the name of the application and a short description of what |
| 644 | content can be searched from the application and made available for suggestions in Quick Search Box. |
| 645 | To define the description text for your searchable application, add the {@code |
| 646 | android:searchSettingsDescription} attribute to your searchable configuration. For example:</p> |
| 647 | |
| 648 | <pre> |
| 649 | <?xml version="1.0" encoding="utf-8"?> |
| 650 | <searchable xmlns:android="http://schemas.android.com/apk/res/android" |
| 651 | android:label="@string/app_label" |
| 652 | android:hint="@string/search_hint" |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 653 | android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider" |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 654 | android:searchSuggestIntentAction="android.intent.action.VIEW" |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 655 | android:includeInGlobalSearch="true" |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 656 | <b>android:searchSettingsDescription="@string/search_description"</b> > |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 657 | </searchable> |
| 658 | </pre> |
| 659 | |
| 660 | <p>The string for {@code android:searchSettingsDescription} should be as concise as possible and |
| 661 | state the content that is searchable. For example, "Artists, albums, and tracks" for a music |
| 662 | application, or "Saved notes" for a notepad application. Providing this description is important so |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 663 | the user knows what kind of suggestions are provided. You should always include this attribute |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 664 | when {@code android:includeInGlobalSearch} is "true".</p> |
| 665 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 666 | <p>Remember that the user must visit the settings menu to enable search suggestions for your |
| 667 | application before your search suggestions appear in Quick Search Box. As such, if search is an |
| 668 | important aspect of your application, then you might want to consider a way to convey that to |
| 669 | your users — you might provide a note the first time they launch the app that instructs |
| 670 | them how to enable search suggestions for Quick Search Box.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 671 | |
| 672 | |
| 673 | <h3 id="ManagingShortcuts">Managing Quick Search Box suggestion shortcuts</h3> |
| 674 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 675 | <p>Suggestions that the user selects from Quick Search Box can be automatically made into shortcuts. |
Scott Main | abdf0d5 | 2011-02-08 10:20:27 -0800 | [diff] [blame] | 676 | These are suggestions that the system has copied from your content provider so it can |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 677 | quickly 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 Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 680 | suggestion data changes over time, then you can request that the shortcuts be refreshed. For |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 681 | instance, if your suggestions refer to dynamic data, such as a contact's presence status, then you |
| 682 | should request that the suggestion shortcuts be refreshed when shown to the user. To do so, |
| 683 | include the {@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} in your suggestions table. |
| 684 | Using this column, you can |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 685 | configure the shortcut behavior for each suggestion in one of the following ways:</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 686 | |
| 687 | <ol type="a"> |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 688 | <li>Have Quick Search Box re-query your content provider for a fresh version of the suggestion |
| 689 | shortcut. |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 690 | <p>Provide a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} column |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 691 | and the suggestion is |
| 692 | re-queried for a fresh version each time the shortcut is displayed. The shortcut |
| 693 | is quickly displayed with whatever data was most recently available until the refresh query |
| 694 | returns, at which point the suggestion is refreshed with the new information. The |
| 695 | refresh query is sent to your content provider with a URI path of {@link |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 696 | android.app.SearchManager#SUGGEST_URI_PATH_SHORTCUT} |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 697 | (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 Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 699 | same columns as the original suggestion, or be empty, indicating that the shortcut is no |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 700 | longer 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 |
| 702 | refresh, you can also add the {@link |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 703 | android.app.SearchManager#SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING} column to your suggestions |
| 704 | table with a value |
| 705 | of "true" in order to show a progress spinner for the right hand icon until the refresh is complete. |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 706 | Any value other than "true" does not show the progress spinner.</p> |
| 707 | </li> |
| 708 | |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 709 | <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 Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 712 | this case, the suggestion is never copied into a shortcut. This should only be necessary if you |
| 713 | absolutely do not want the previously copied suggestion to appear. (Recall that if you |
| 714 | provide a normal value for the column, then the suggestion shortcut appears only until the |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 715 | refresh query returns.)</p></li> |
| 716 | <li>Allow the default shortcut behavior to apply. |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 717 | <p>Leave the {@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} empty for each |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 718 | suggestion that will not change and can be saved as a shortcut.</p></li> |
| 719 | </ol> |
| 720 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 721 | <p>If none of your suggestions ever change, then you do not need the |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 722 | {@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} column at all.</p> |
| 723 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 724 | <p class="note"><strong>Note</strong>: Quick Search Box ultimately decides whether or not to create |
| 725 | a shortcut for a suggestion, considering these values as a strong request from your |
| 726 | application—there is no guarantee that the behavior you have requested for your suggestion |
| 727 | shortcuts will be honored.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 728 | |
| 729 | |
| 730 | <h3 id="AboutRanking">About Quick Search Box suggestion ranking</h3> |
| 731 | |
Scott Main | 5e892d8 | 2010-05-25 17:04:01 -0700 | [diff] [blame] | 732 | <p>Once you make your application's search suggestions available to Quick Search Box, the Quick |
| 733 | Search Box ranking determines how the suggestions are surfaced to the user for a particular query. |
| 734 | This might depend on how many other apps have results for that query, and how often the user has |
| 735 | selected your results compared to those from other apps. There is no guarantee about how your |
| 736 | suggestions are ranked, or whether your app's suggestions show at all for a given query. In |
| 737 | general, you can expect that providing quality results increases the likelihood that your app's |
| 738 | suggestions are provided in a prominent position and apps that provide low quality suggestions |
| 739 | are more likely to be ranked lower or not displayed.</p> |
Scott Main | b3b2b4f | 2010-02-12 17:19:02 -0800 | [diff] [blame] | 740 | |
| 741 | <div class="special"> |
| 742 | <p>See the <a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable |
| 743 | Dictionary sample app</a> for a complete demonstration of custom search suggestions.</p> |
| 744 | </div> |
| 745 | |