SearchManager.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.app;
18
19import android.content.ComponentName;
20import android.content.Context;
21import android.content.DialogInterface;
22import android.content.res.Configuration;
23import android.os.Bundle;
24import android.os.Handler;
25import android.os.ServiceManager;
26import android.view.KeyEvent;
27
28/**
29 * This class provides access to the system search services.
30 *
31 * <p>In practice, you won't interact with this class directly, as search
32 * services are provided through methods in {@link android.app.Activity Activity}
33 * methods and the the {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH}
34 * {@link android.content.Intent Intent}.  This class does provide a basic
35 * overview of search services and how to integrate them with your activities.
36 * If you do require direct access to the Search Manager, do not instantiate
37 * this class directly; instead, retrieve it through
38 * {@link android.content.Context#getSystemService
39 * context.getSystemService(Context.SEARCH_SERVICE)}.
40 *
41 * <p>Topics covered here:
42 * <ol>
43 * <li><a href="#DeveloperGuide">Developer Guide</a>
44 * <li><a href="#HowSearchIsInvoked">How Search Is Invoked</a>
45 * <li><a href="#QuerySearchApplications">Query-Search Applications</a>
46 * <li><a href="#FilterSearchApplications">Filter-Search Applications</a>
47 * <li><a href="#Suggestions">Search Suggestions</a>
48 * <li><a href="#ActionKeys">Action Keys</a>
49 * <li><a href="#SearchabilityMetadata">Searchability Metadata</a>
50 * <li><a href="#PassingSearchContext">Passing Search Context</a>
51 * </ol>
52 *
53 * <a name="DeveloperGuide"></a>
54 * <h3>Developer Guide</h3>
55 *
56 * <p>The ability to search for user, system, or network based data is considered to be
57 * a core user-level feature of the android platform.  At any time, the user should be
58 * able to use a familiar command, button, or keystroke to invoke search, and the user
59 * should be able to search any data which is available to them.  The goal is to make search
60 * appear to the user as a seamless, system-wide feature.
61 *
62 * <p>In terms of implementation, there are three broad classes of Applications:
63 * <ol>
64 * <li>Applications that are not inherently searchable</li>
65 * <li>Query-Search Applications</li>
66 * <li>Filter-Search Applications</li>
67 * </ol>
68 * <p>These categories, as well as related topics, are discussed in
69 * the sections below.
70 *
71 * <p>Even if your application is not <i>searchable</i>, it can still support the invocation of
72 * search.  Please review the section <a href="#HowSearchIsInvoked">How Search Is Invoked</a>
73 * for more information on how to support this.
74 *
75 * <p>Many applications are <i>searchable</i>.  These are
76 * the applications which can convert a query string into a list of results.
77 * Within this subset, applications can be grouped loosely into two families:
78 * <ul><li><i>Query Search</i> applications perform batch-mode searches - each query string is
79 * converted to a list of results.</li>
80 * <li><i>Filter Search</i> applications provide live filter-as-you-type searches.</li></ul>
81 * <p>Generally speaking, you would use query search for network-based data, and filter
82 * search for local data, but this is not a hard requirement and applications
83 * are free to use the model that fits them best (or invent a new model).
84 * <p>It should be clear that the search implementation decouples "search
85 * invocation" from "searchable".  This satisfies the goal of making search appear
86 * to be "universal".  The user should be able to launch any search from
87 * almost any context.
88 *
89 * <a name="HowSearchIsInvoked"></a>
90 * <h3>How Search Is Invoked</h3>
91 *
92 * <p>Unless impossible or inapplicable, all applications should support
93 * invoking the search UI.  This means that when the user invokes the search command,
94 * a search UI will be presented to them.  The search command is currently defined as a menu
95 * item called "Search" (with an alphabetic shortcut key of "S"), or on some devices, a dedicated
96 * search button key.
97 * <p>If your application is not inherently searchable, you can also allow the search UI
98 * to be invoked in a "web search" mode.  If the user enters a search term and clicks the
99 * "Search" button, this will bring the browser to the front and will launch a web-based
100 * search.  The user will be able to click the "Back" button and return to your application.
101 * <p>In general this is implemented by your activity, or the {@link android.app.Activity Activity}
102 * base class, which captures the search command and invokes the Search Manager to
103 * display and operate the search UI.  You can also cause the search UI to be presented in response
104 * to user keystrokes in your activity (for example, to instantly start filter searching while
105 * viewing a list and typing any key).
106 * <p>The search UI is presented as a floating
107 * window and does not cause any change in the activity stack.  If the user
108 * cancels search, the previous activity re-emerges.  If the user launches a
109 * search, this will be done by sending a search {@link android.content.Intent Intent} (see below),
110 * and the normal intent-handling sequence will take place (your activity will pause,
111 * etc.)
112 * <p><b>What you need to do:</b> First, you should consider the way in which you want to
113 * handle invoking search.  There are four broad (and partially overlapping) categories for
114 * you to choose from.
115 * <ul><li>You can capture the search command yourself, by including a <i>search</i>
116 * button or menu item - and invoking the search UI directly.</li>
117 * <li>You can provide a <i>type-to-search</i> feature, in which search is invoked automatically
118 * when the user enters any characters.</li>
119 * <li>Even if your application is not inherently searchable, you can allow web search,
120 * via the search key (or even via a search menu item).
121 * <li>You can disable search entirely.  This should only be used in very rare circumstances,
122 * as search is a system-wide feature and users will expect it to be available in all contexts.</li>
123 * </ul>
124 *
125 * <p><b>How to define a search menu.</b>  The system provides the following resources which may
126 * be useful when adding a search item to your menu:
127 * <ul><li>android.R.drawable.ic_search_category_default is an icon you can use in your menu.</li>
128 * <li>{@link #MENU_KEY SearchManager.MENU_KEY} is the recommended alphabetic shortcut.</li>
129 * </ul>
130 *
131 * <p><b>How to invoke search directly.</b>  In order to invoke search directly, from a button
132 * or menu item, you can launch a generic search by calling
133 * {@link android.app.Activity#onSearchRequested onSearchRequested} as shown:
134 * <pre class="prettyprint">
135 * onSearchRequested();</pre>
136 *
137 * <p><b>How to implement type-to-search.</b>  While setting up your activity, call
138 * {@link android.app.Activity#setDefaultKeyMode setDefaultKeyMode}:
139 * <pre class="prettyprint">
140 * setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);   // search within your activity
141 * setDefaultKeyMode(DEFAULT_KEYS_SEARCH_GLOBAL);  // search using platform global search</pre>
142 *
143 * <p><b>How to enable web-based search.</b>  In addition to searching within your activity or
144 * application, you can also use the Search Manager to invoke a platform-global search, typically
145 * a web search.  There are two ways to do this:
146 * <ul><li>You can simply define "search" within your application or activity to mean global search.
147 * This is described in more detail in the
148 * <a href="#SearchabilityMetadata">Searchability Metadata</a> section.  Briefly, you will
149 * add a single meta-data entry to your manifest, declaring that the default search
150 * for your application is "*".  This indicates to the system that no application-specific
151 * search activity is provided, and that it should launch web-based search instead.</li>
152 * <li>You can specify this at invocation time via default keys (see above), overriding
153 * {@link android.app.Activity#onSearchRequested}, or via a direct call to
154 * {@link android.app.Activity#startSearch}.  This is most useful if you wish to provide local
155 * searchability <i>and</i> access to global search.</li></ul>
156 *
157 * <p><b>How to disable search from your activity.</b>  search is a system-wide feature and users
158 * will expect it to be available in all contexts.  If your UI design absolutely precludes
159 * launching search, override {@link android.app.Activity#onSearchRequested onSearchRequested}
160 * as shown:
161 * <pre class="prettyprint">
162 * &#64;Override
163 * public boolean onSearchRequested() {
164 *    return false;
165 * }</pre>
166 *
167 * <p><b>Managing focus and knowing if Search is active.</b>  The search UI is not a separate
168 * activity, and when the UI is invoked or dismissed, your activity will not typically be paused,
169 * resumed, or otherwise notified by the methods defined in
170 * <a href="android.app.Activity#ActivityLifecycle">Activity Lifecycle</a>.  The search UI is
171 * handled in the same way as other system UI elements which may appear from time to time, such as
172 * notifications, screen locks, or other system alerts:
173 * <p>When the search UI appears, your activity will lose input focus.
174 * <p>When the search activity is dismissed, there are three possible outcomes:
175 * <ul><li>If the user simply canceled the search UI, your activity will regain input focus and
176 * proceed as before.  See {@link #setOnDismissListener} and {@link #setOnCancelListener} if you
177 * required direct notification of search dialog dismissals.</li>
178 * <li>If the user launched a search, and this required switching to another activity to receive
179 * and process the search {@link android.content.Intent Intent}, your activity will receive the
180 * normal sequence of activity pause or stop notifications.</li>
181 * <li>If the user launched a search, and the current activity is the recipient of the search
182 * {@link android.content.Intent Intent}, you will receive notification via the
183 * {@link android.app.Activity#onNewIntent onNewIntent()} method.</li></ul>
184 * <p>This list is provided in order to clarify the ways in which your activities will interact with
185 * the search UI.  More details on searchable activities and search intents are provided in the
186 * sections below.
187 *
188 * <a name="QuerySearchApplications"></a>
189 * <h3>Query-Search Applications</h3>
190 *
191 * <p>Query-search applications are those that take a single query (e.g. a search
192 * string) and present a set of results that may fit.  Primary examples include
193 * web queries, map lookups, or email searches (with the common thread being
194 * network query dispatch).  It may also be the case that certain local searches
195 * are treated this way.  It's up to the application to decide.
196 *
197 * <p><b>What you need to do:</b>  The following steps are necessary in order to
198 * implement query search.
199 * <ul>
200 * <li>Implement search invocation as described above.  (Strictly speaking,
201 * these are decoupled, but it would make little sense to be "searchable" but not
202 * "search-invoking".)</li>
203 * <li>Your application should have an activity that takes a search string and
204 * converts it to a list of results.  This could be your primary display activity
205 * or it could be a dedicated search results activity.  This is your <i>searchable</i>
206 * activity and every query-search application must have one.</li>
207 * <li>In the searchable activity, in onCreate(), you must receive and handle the
208 * {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH}
209 * {@link android.content.Intent Intent}.  The text to search (query string) for is provided by
210 * calling
211 * {@link #QUERY getStringExtra(SearchManager.QUERY)}.</li>
212 * <li>To identify and support your searchable activity, you'll need to
213 * provide an XML file providing searchability configuration parameters, a reference to that
214 * in your searchable activity's <a href="../../../devel/bblocks-manifest.html">manifest</a>
215 * entry, and an intent-filter declaring that you can
216 * receive ACTION_SEARCH intents.  This is described in more detail in the
217 * <a href="#SearchabilityMetadata">Searchability Metadata</a> section.</li>
218 * <li>Your <a href="../../../devel/bblocks-manifest.html">manifest</a> also needs a metadata entry
219 * providing a global reference to the searchable activity.  This is the "glue" directing the search
220 * UI, when invoked from any of your <i>other</i> activities, to use your application as the
221 * default search context.  This is also described in more detail in the
222 * <a href="#SearchabilityMetadata">Searchability Metadata</a> section.</li>
223 * <li>Finally, you may want to define your search results activity as with the
224 * {@link android.R.attr#launchMode singleTop} launchMode flag.  This allows the system
225 * to launch searches from/to the same activity without creating a pile of them on the
226 * activity stack.  If you do this, be sure to also override
227 * {@link android.app.Activity#onNewIntent onNewIntent} to handle the
228 * updated intents (with new queries) as they arrive.</li>
229 * </ul>
230 *
231 * <p>Code snippet showing handling of intents in your search activity:
232 * <pre class="prettyprint">
233 * &#64;Override
234 * protected void onCreate(Bundle icicle) {
235 *     super.onCreate(icicle);
236 *
237 *     final Intent queryIntent = getIntent();
238 *     final String queryAction = queryIntent.getAction();
239 *     if (Intent.ACTION_SEARCH.equals(queryAction)) {
240 *         doSearchWithIntent(queryIntent);
241 *     }
242 * }
243 *
244 * private void doSearchWithIntent(final Intent queryIntent) {
245 *     final String queryString = queryIntent.getStringExtra(SearchManager.QUERY);
246 *     doSearchWithQuery(queryString);
247 * }</pre>
248 *
249 * <a name="FilterSearchApplications"></a>
250 * <h3>Filter-Search Applications</h3>
251 *
252 * <p>Filter-search applications are those that use live text entry (e.g. keystrokes)) to
253 * display and continuously update a list of results.  Primary examples include applications
254 * that use locally-stored data.
255 *
256 * <p>Filter search is not directly supported by the Search Manager.  Most filter search
257 * implementations will use variants of {@link android.widget.Filterable}, such as a
258 * {@link android.widget.ListView} bound to a {@link android.widget.SimpleCursorAdapter}.  However,
259 * you may find it useful to mix them together, by declaring your filtered view searchable.  With
260 * this configuration, you can still present the standard search dialog in all activities
261 * within your application, but transition to a filtered search when you enter the activity
262 * and display the results.
263 *
264 * <a name="Suggestions"></a>
265 * <h3>Search Suggestions</h3>
266 *
267 * <p>A powerful feature of the Search Manager is the ability of any application to easily provide
268 * live "suggestions" in order to prompt the user.  Each application implements suggestions in a
269 * different, unique, and appropriate way.  Suggestions be drawn from many sources, including but
270 * not limited to:
271 * <ul>
272 * <li>Actual searchable results (e.g. names in the address book)</li>
273 * <li>Recently entered queries</li>
274 * <li>Recently viewed data or results</li>
275 * <li>Contextually appropriate queries or results</li>
276 * <li>Summaries of possible results</li>
277 * </ul>
278 *
279 * <p>Another feature of suggestions is that they can expose queries or results before the user
280 * ever visits the application.  This reduces the amount of context switching required, and helps
281 * the user access their data quickly and with less context shifting.  In order to provide this
282 * capability, suggestions are accessed via a
283 * {@link android.content.ContentProvider Content Provider}.
284 *
285 * <p>The primary form of suggestions is known as <i>queried suggestions</i> and is based on query
286 * text that the user has already typed.  This would generally be based on partial matches in
287 * the available data.  In certain situations - for example, when no query text has been typed yet -
288 * an application may also opt to provide <i>zero-query suggestions</i>.
289 * These would typically be drawn from the same data source, but because no partial query text is
290 * available, they should be weighted based on other factors - for example, most recent queries
291 * or most recent results.
292 *
293 * <p><b>Overview of how suggestions are provided.</b>  When the search manager identifies a
294 * particular activity as searchable, it will check for certain metadata which indicates that
295 * there is also a source of suggestions.  If suggestions are provided, the following steps are
296 * taken.
297 * <ul><li>Using formatting information found in the metadata, the user's query text (whatever
298 * has been typed so far) will be formatted into a query and sent to the suggestions
299 * {@link android.content.ContentProvider Content Provider}.</li>
300 * <li>The suggestions {@link android.content.ContentProvider Content Provider} will create a
301 * {@link android.database.Cursor Cursor} which can iterate over the possible suggestions.</li>
302 * <li>The search manager will populate a list using display data found in each row of the cursor,
303 * and display these suggestions to the user.</li>
304 * <li>If the user types another key, or changes the query in any way, the above steps are repeated
305 * and the suggestions list is updated or repopulated.</li>
306 * <li>If the user clicks or touches the "GO" button, the suggestions are ignored and the search is
307 * launched using the normal {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} type of
308 * {@link android.content.Intent Intent}.</li>
309 * <li>If the user uses the directional controls to navigate the focus into the suggestions list,
310 * the query text will be updated while the user navigates from suggestion to suggestion.  The user
311 * can then click or touch the updated query and edit it further.  If the user navigates back to
312 * the edit field, the original typed query is restored.</li>
313 * <li>If the user clicks or touches a particular suggestion, then a combination of data from the
314 * cursor and
315 * values found in the metadata are used to synthesize an Intent and send it to the application.
316 * Depending on the design of the activity and the way it implements search, this might be a
317 * {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} (in order to launch a query), or it
318 * might be a {@link android.content.Intent#ACTION_VIEW ACTION_VIEW}, in order to proceed directly
319 * to display of specific data.</li>
320 * </ul>
321 *
322 * <p><b>Simple Recent-Query-Based Suggestions.</b>  The Android framework provides a simple Search
323 * Suggestions provider, which simply records and replays recent queries.  For many applications,
324 * this will be sufficient.  The basic steps you will need to
325 * do, in order to use the built-in recent queries suggestions provider, are as follows:
326 * <ul>
327 * <li>Implement and test query search, as described in the previous sections.</li>
328 * <li>Create a Provider within your application by extending
329 * {@link android.content.SearchRecentSuggestionsProvider}.</li>
330 * <li>Create a manifest entry describing your provider.</li>
331 * <li>Update your searchable activity's XML configuration file with information about your
332 * provider.</li>
333 * <li>In your searchable activities, capture any user-generated queries and record them
334 * for future searches by calling {@link android.provider.SearchRecentSuggestions#saveRecentQuery}.
335 * </li>
336 * </ul>
337 * <p>For complete implementation details, please refer to
338 * {@link android.content.SearchRecentSuggestionsProvider}.  The rest of the information in this
339 * section should not be necessary, as it refers to custom suggestions providers.
340 *
341 * <p><b>Creating a Customized Suggestions Provider:</b>  In order to create more sophisticated
342 * suggestion providers, you'll need to take the following steps:
343 * <ul>
344 * <li>Implement and test query search, as described in the previous sections.</li>
345 * <li>Decide how you wish to <i>receive</i> suggestions.  Just like queries that the user enters,
346 * suggestions will be delivered to your searchable activity as
347 * {@link android.content.Intent Intent} messages;  Unlike simple queries, you have quite a bit of
348 * flexibility in forming those intents.  A query search application will probably
349 * wish to continue receiving the {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH}
350 * {@link android.content.Intent Intent}, which will launch a query search using query text as
351 * provided by the suggestion.  A filter search application will probably wish to
352 * receive the {@link android.content.Intent#ACTION_VIEW ACTION_VIEW}
353 * {@link android.content.Intent Intent}, which will take the user directly to a selected entry.
354 * Other interesting suggestions, including hybrids, are possible, and the suggestion provider
355 * can easily mix-and-match results to provide a richer set of suggestions for the user.  Finally,
356 * you'll need to update your searchable activity (or other activities) to receive the intents
357 * as you've defined them.</li>
358 * <li>Implement a Content Provider that provides suggestions.  If you already have one, and it
359 * has access to your suggestions data.  If not, you'll have to create one.
360 * You'll also provide information about your Content Provider in your
361 * package's <a href="../../../devel/bblocks-manifest.html">manifest</a>.</li>
362 * <li>Update your searchable activity's XML configuration file.  There are two categories of
363 * information used for suggestions:
364 * <ul><li>The first is (required) data that the search manager will
365 * use to format the queries which are sent to the Content Provider.</li>
366 * <li>The second is (optional) parameters to configure structure
367 * if intents generated by suggestions.</li></li>
368 * </ul>
369 * </ul>
370 *
371 * <p><b>Configuring your Content Provider to Receive Suggestion Queries.</b>  The basic job of
372 * a search suggestions {@link android.content.ContentProvider Content Provider} is to provide
373 * "live" (while-you-type) conversion of the user's query text into a set of zero or more
374 * suggestions.  Each application is free to define the conversion, and as described above there are
375 * many possible solutions.  This section simply defines how to communicate with the suggestion
376 * provider.
377 *
378 * <p>The Search Manager must first determine if your package provides suggestions.  This is done
379 * by examination of your searchable meta-data XML file.  The android:searchSuggestAuthority
380 * attribute, if provided, is the signal to obtain & display suggestions.
381 *
382 * <p>Every query includes a Uri, and the Search Manager will format the Uri as shown:
383 * <p><pre class="prettyprint">
384 * content:// your.suggest.authority / your.suggest.path / SearchManager.SUGGEST_URI_PATH_QUERY</pre>
385 *
386 * <p>Your Content Provider can receive the query text in one of two ways.
387 * <ul>
388 * <li><b>Query provided as a selection argument.</b>  If you define the attribute value
389 * android:searchSuggestSelection and include a string, this string will be passed as the
390 * <i>selection</i> parameter to your Content Provider's query function.  You must define a single
391 * selection argument, using the '?' character.  The user's query text will be passed to you
392 * as the first element of the selection arguments array.</li>
393 * <li><b>Query provided with Data Uri.</b>  If you <i>do not</i> define the attribute value
394 * android:searchSuggestSelection, then the Search Manager will append another "/" followed by
395 * the user's query to the query Uri.  The query will be encoding using Uri encoding rules - don't
396 * forget to decode it.  (See {@link android.net.Uri#getPathSegments} and
397 * {@link android.net.Uri#getLastPathSegment} for helpful utilities you can use here.)</li>
398 * </ul>
399 *
400 * <p><b>Handling empty queries.</b>  Your application should handle the "empty query"
401 * (no user text entered) case properly, and generate useful suggestions in this case.  There are a
402 * number of ways to do this;  Two are outlined here:
403 * <ul><li>For a simple filter search of local data, you could simply present the entire dataset,
404 * unfiltered.  (example: People)</li>
405 * <li>For a query search, you could simply present the most recent queries.  This allows the user
406 * to quickly repeat a recent search.</li></ul>
407 *
408 * <p><b>The Format of Individual Suggestions.</b>  Your suggestions are communicated back to the
409 * Search Manager by way of a {@link android.database.Cursor Cursor}.  The Search Manager will
410 * usually pass a null Projection, which means that your provider can simply return all appropriate
411 * columns for each suggestion.  The columns currently defined are:
412 *
413 * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
414 *
415 *     <thead>
416 *     <tr><th>Column Name</th> <th>Description</th> <th>Required?</th></tr>
417 *     </thead>
418 *
419 *     <tbody>
420 *     <tr><th>{@link #SUGGEST_COLUMN_FORMAT}</th>
421 *         <td><i>Unused - can be null.</i></td>
422 *         <td align="center">No</td>
423 *     </tr>
424 *
425 *     <tr><th>{@link #SUGGEST_COLUMN_TEXT_1}</th>
426 *         <td>This is the line of text that will be presented to the user as the suggestion.</td>
427 *         <td align="center">Yes</td>
428 *     </tr>
429 *
430 *     <tr><th>{@link #SUGGEST_COLUMN_TEXT_2}</th>
431 *         <td>If your cursor includes this column, then all suggestions will be provided in a
432 *             two-line format.  The data in this column will be displayed as a second, smaller
433 *             line of text below the primary suggestion, or it can be null or empty to indicate no
434 *             text in this row's suggestion.</td>
435 *         <td align="center">No</td>
436 *     </tr>
437 *
438 *     <tr><th>{@link #SUGGEST_COLUMN_ICON_1}</th>
439 *         <td>If your cursor includes this column, then all suggestions will be provided in an
440 *             icons+text format.  This value should be a reference (resource ID) of the icon to
441 *             draw on the left side, or it can be null or zero to indicate no icon in this row.
442 *             You must provide both cursor columns, or neither.
443 *             </td>
444 *         <td align="center">No, but required if you also have {@link #SUGGEST_COLUMN_ICON_2}</td>
445 *     </tr>
446 *
447 *     <tr><th>{@link #SUGGEST_COLUMN_ICON_2}</th>
448 *         <td>If your cursor includes this column, then all suggestions will be provided in an
449 *             icons+text format.  This value should be a reference (resource ID) of the icon to
450 *             draw on the right side, or it can be null or zero to indicate no icon in this row.
451 *             You must provide both cursor columns, or neither.
452 *             </td>
453 *         <td align="center">No, but required if you also have {@link #SUGGEST_COLUMN_ICON_1}</td>
454 *     </tr>
455 *
456 *     <tr><th>{@link #SUGGEST_COLUMN_INTENT_ACTION}</th>
457 *         <td>If this column exists <i>and</i> this element exists at the given row, this is the
458 *             action that will be used when forming the suggestion's intent.  If the element is
459 *             not provided, the action will be taken from the android:searchSuggestIntentAction
460 *             field in your XML metadata.  <i>At least one of these must be present for the
461 *             suggestion to generate an intent.</i>  Note:  If your action is the same for all
462 *             suggestions, it is more efficient to specify it using XML metadata and omit it from
463 *             the cursor.</td>
464 *         <td align="center">No</td>
465 *     </tr>
466 *
467 *     <tr><th>{@link #SUGGEST_COLUMN_INTENT_DATA}</th>
468 *         <td>If this column exists <i>and</i> this element exists at the given row, this is the
469 *             data that will be used when forming the suggestion's intent.  If the element is not
470 *             provided, the data will be taken from the android:searchSuggestIntentData field in
471 *             your XML metadata.  If neither source is provided, the Intent's data field will be
472 *             null.  Note:  If your data is the same for all suggestions, or can be described
473 *             using a constant part and a specific ID, it is more efficient to specify it using
474 *             XML metadata and omit it from the cursor.</td>
475 *         <td align="center">No</td>
476 *     </tr>
477 *
478 *     <tr><th>{@link #SUGGEST_COLUMN_INTENT_DATA_ID}</th>
479 *         <td>If this column exists <i>and</i> this element exists at the given row, then "/" and
480 *             this value will be appended to the data field in the Intent.  This should only be
481 *             used if the data field has already been set to an appropriate base string.</td>
482 *         <td align="center">No</td>
483 *     </tr>
484 *
485 *     <tr><th>{@link #SUGGEST_COLUMN_QUERY}</th>
486 *         <td>If this column exists <i>and</i> this element exists at the given row, this is the
487 *             data that will be used when forming the suggestion's query.</td>
488 *         <td align="center">Required if suggestion's action is
489 *             {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH}, optional otherwise.</td>
490 *     </tr>
491 *
492 *     <tr><th><i>Other Columns</i></th>
493 *         <td>Finally, if you have defined any <a href="#ActionKeys">Action Keys</a> and you wish
494 *             for them to have suggestion-specific definitions, you'll need to define one
495 *             additional column per action key.  The action key will only trigger if the
496 *             currently-selection suggestion has a non-empty string in the corresponding column.
497 *             See the section on <a href="#ActionKeys">Action Keys</a> for additional details and
498 *             implementation steps.</td>
499 *         <td align="center">No</td>
500 *     </tr>
501 *
502 *     </tbody>
503 * </table>
504 *
505 * <p>Clearly there are quite a few permutations of your suggestion data, but in the next section
506 * we'll look at a few simple combinations that you'll select from.
507 *
508 * <p><b>The Format Of Intents Sent By Search Suggestions.</b>  Although there are many ways to
509 * configure these intents, this document will provide specific information on just a few of them.
510 * <ul><li><b>Launch a query.</b>  In this model, each suggestion represents a query that your
511 * searchable activity can perform, and the {@link android.content.Intent Intent} will be formatted
512 * exactly like those sent when the user enters query text and clicks the "GO" button:
513 *   <ul>
514 *   <li><b>Action:</b> {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} provided
515 *   using your XML metadata (android:searchSuggestIntentAction).</li>
516 *   <li><b>Data:</b> empty (not used).</li>
517 *   <li><b>Query:</b> query text supplied by the cursor.</li>
518 *   </ul>
519 * </li>
520 * <li><b>Go directly to a result, using a complete Data Uri.</b>  In this model, the user will be
521 * taken directly to a specific result.
522 *   <ul>
523 *   <li><b>Action:</b> {@link android.content.Intent#ACTION_VIEW ACTION_VIEW}</li>
524 *   <li><b>Data:</b> a complete Uri, supplied by the cursor, that identifies the desired data.</li>
525 *   <li><b>Query:</b> query text supplied with the suggestion (probably ignored)</li>
526 *   </ul>
527 * </li>
528 * <li><b>Go directly to a result, using a synthesized Data Uri.</b>  This has the same result
529 * as the previous suggestion, but provides the Data Uri in a different way.
530 *   <ul>
531 *   <li><b>Action:</b> {@link android.content.Intent#ACTION_VIEW ACTION_VIEW}</li>
532 *   <li><b>Data:</b> The search manager will assemble a Data Uri using the following elements:
533 *   a Uri fragment provided in your XML metadata (android:searchSuggestIntentData), followed by
534 *   a single "/", followed by the value found in the {@link #SUGGEST_COLUMN_INTENT_DATA_ID}
535 *   entry in your cursor.</li>
536 *   <li><b>Query:</b> query text supplied with the suggestion (probably ignored)</li>
537 *   </ul>
538 * </li>
539 * </ul>
540 * <p>This list is not meant to be exhaustive.  Applications should feel free to define other types
541 * of suggestions.  For example, you could reduce long lists of results to summaries, and use one
542 * of the above intents (or one of your own) with specially formatted Data Uri's to display more
543 * detailed results.  Or you could display textual shortcuts as suggestions, but launch a display
544 * in a more data-appropriate format such as media artwork.
545 *
546 * <p><b>Suggestion Rewriting.</b>  If the user navigates through the suggestions list, the UI
547 * may temporarily rewrite the user's query with a query that matches the currently selected
548 * suggestion.  This enables the user to see what query is being suggested, and also allows the user
549 * to click or touch in the entry EditText element and make further edits to the query before
550 * dispatching it.  In order to perform this correctly, the Search UI needs to know exactly what
551 * text to rewrite the query with.
552 *
553 * <p>For each suggestion, the following logic is used to select a new query string:
554 * <ul><li>If the suggestion provides an explicit value in the {@link #SUGGEST_COLUMN_QUERY}
555 * column, this value will be used.</li>
556 * <li>If the metadata includes the queryRewriteFromData flag, and the suggestion provides an
557 * explicit value for the intent Data field, this Uri will be used.  Note that this should only be
558 * used with Uri's that are intended to be user-visible, such as HTTP.  Internal Uri schemes should
559 * not be used in this way.</li>
560 * <li>If the metadata includes the queryRewriteFromText flag, the text in
561 * {@link #SUGGEST_COLUMN_TEXT_1} will be used.  This should be used for suggestions in which no
562 * query text is provided and the SUGGEST_COLUMN_INTENT_DATA values are not suitable for user
563 * inspection and editing.</li></ul>
564 *
565 * <a name="ActionKeys"></a>
566 * <h3>Action Keys</h3>
567 *
568 * <p>Searchable activities may also wish to provide shortcuts based on the various action keys
569 * available on the device.  The most basic example of this is the contacts app, which enables the
570 * green "dial" key for quick access during searching.  Not all action keys are available on
571 * every device, and not all are allowed to be overriden in this way.  (For example, the "Home"
572 * key must always return to the home screen, with no exceptions.)
573 *
574 * <p>In order to define action keys for your searchable application, you must do two things.
575 *
576 * <ul>
577 * <li>You'll add one or more <i>actionkey</i> elements to your searchable metadata configuration
578 * file.  Each element defines one of the keycodes you are interested in,
579 * defines the conditions under which they are sent, and provides details
580 * on how to communicate the action key event back to your searchable activity.</li>
581 * <li>In your intent receiver, if you wish, you can check for action keys by checking the
582 * extras field of the {@link android.content.Intent Intent}.</li>
583 * </ul>
584 *
585 * <p><b>Updating metadata.</b>  For each keycode of interest, you must add an &lt;actionkey&gt;
586 * element.  Within this element you must define two or three attributes.  The first attribute,
587 * &lt;android:keycode&gt;, is required;  It is the key code of the action key event, as defined in
588 * {@link android.view.KeyEvent}.  The remaining two attributes define the value of the actionkey's
589 * <i>message</i>, which will be passed to your searchable activity in the
590 * {@link android.content.Intent Intent} (see below for more details).  Although each of these
591 * attributes is optional, you must define one or both for the action key to have any effect.
592 * &lt;android:queryActionMsg&gt; provides the message that will be sent if the action key is
593 * pressed while the user is simply entering query text.  &lt;android:suggestActionMsgColumn&gt;
594 * is used when action keys are tied to specific suggestions.  This attribute provides the name
595 * of a <i>column</i> in your suggestion cursor;  The individual suggestion, in that column,
596 * provides the message.  (If the cell is empty or null, that suggestion will not work with that
597 * action key.)
598 * <p>See the <a href="#SearchabilityMetadata">Searchability Metadata</a> section for more details
599 * and examples.
600 *
601 * <p><b>Receiving Action Keys</b>  Intents launched by action keys will be specially marked
602 * using a combination of values.  This enables your searchable application to examine the intent,
603 * if necessary, and perform special processing.  For example, clicking a suggested contact might
604 * simply display them;  Selecting a suggested contact and clicking the dial button might
605 * immediately call them.
606 *
607 * <p>When a search {@link android.content.Intent Intent} is launched by an action key, two values
608 * will be added to the extras field.
609 * <ul>
610 * <li>To examine the key code, use {@link android.content.Intent#getIntExtra
611 * getIntExtra(SearchManager.ACTION_KEY)}.</li>
612 * <li>To examine the message string, use {@link android.content.Intent#getStringExtra
613 * getStringExtra(SearchManager.ACTION_MSG)}</li>
614 * </ul>
615 *
616 * <a name="SearchabilityMetadata"></a>
617 * <h3>Searchability Metadata</h3>
618 *
619 * <p>Every activity that is searchable must provide a small amount of additional information
620 * in order to properly configure the search system.  This controls the way that your search
621 * is presented to the user, and controls for the various modalities described previously.
622 *
623 * <p>If your application is not searchable,
624 * then you do not need to provide any search metadata, and you can skip the rest of this section.
625 * When this search metadata cannot be found, the search manager will assume that the activity
626 * does not implement search.  (Note: to implement web-based search, you will need to add
627 * the android.app.default_searchable metadata to your manifest, as shown below.)
628 *
629 * <p>Values you supply in metadata apply only to each local searchable activity.  Each
630 * searchable activity can define a completely unique search experience relevant to its own
631 * capabilities and user experience requirements, and a single application can even define multiple
632 * searchable activities.
633 *
634 * <p><b>Metadata for searchable activity.</b>  As with your search implementations described
635 * above, you must first identify which of your activities is searchable.  In the
636 * <a href="../../../devel/bblocks-manifest.html">manifest</a> entry for this activity, you must
637 * provide two elements:
638 * <ul><li>An intent-filter specifying that you can receive and process the
639 * {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} {@link android.content.Intent Intent}.
640 * </li>
641 * <li>A reference to a small XML file (typically called "searchable.xml") which contains the
642 * remaining configuration information for how your application implements search.</li></ul>
643 *
644 * <p>Here is a snippet showing the necessary elements in the
645 * <a href="../../../devel/bblocks-manifest.html">manifest</a> entry for your searchable activity.
646 * <pre class="prettyprint">
647 *        &lt;!-- Search Activity - searchable --&gt;
648 *        &lt;activity android:name="MySearchActivity"
649 *                  android:label="Search"
650 *                  android:launchMode="singleTop"&gt;
651 *            &lt;intent-filter&gt;
652 *                &lt;action android:name="android.intent.action.SEARCH" /&gt;
653 *                &lt;category android:name="android.intent.category.DEFAULT" /&gt;
654 *            &lt;/intent-filter&gt;
655 *            &lt;meta-data android:name="android.app.searchable"
656 *                       android:resource="@xml/searchable" /&gt;
657 *        &lt;/activity&gt;</pre>
658 *
659 * <p>Next, you must provide the rest of the searchability configuration in
660 * the small XML file, stored in the ../xml/ folder in your build.  The XML file is a
661 * simple enumeration of the search configuration parameters for searching within this activity,
662 * application, or package.  Here is a sample XML file (named searchable.xml, for use with
663 * the above manifest) for a query-search activity.
664 *
665 * <pre class="prettyprint">
666 * &lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
667 *     android:label="@string/search_label"
668 *     android:hint="@string/search_hint" &gt;
669 * &lt;/searchable&gt;</pre>
670 *
671 * <p>Note that all user-visible strings <i>must</i> be provided in the form of "@string"
672 * references.  Hard-coded strings, which cannot be localized, will not work properly in search
673 * metadata.
674 *
675 * <p>Attributes you can set in search metadata:
676 * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
677 *
678 *     <thead>
679 *     <tr><th>Attribute</th> <th>Description</th> <th>Required?</th></tr>
680 *     </thead>
681 *
682 *     <tbody>
683 *     <tr><th>android:label</th>
684 *         <td>This is the name for your application that will be presented to the user in a
685 *             list of search targets, or in the search box as a label.</td>
686 *         <td align="center">Yes</td>
687 *     </tr>
688 *
689 *     <tr><th>android:icon</th>
690 *         <td>If provided, this icon will be used <i>in place</i> of the label string.  This
691 *         is provided in order to present logos or other non-textual banners.</td>
692 *         <td align="center">No</td>
693 *     </tr>
694 *
695 *     <tr><th>android:hint</th>
696 *         <td>This is the text to display in the search text field when no user text has been
697 *             entered.</td>
698 *         <td align="center">No</td>
699 *     </tr>
700 *
701 *     <tr><th>android:searchButtonText</th>
702 *         <td>If provided, this text will replace the default text in the "Search" button.</td>
703 *         <td align="center">No</td>
704 *     </tr>
705 *
706 *     <tr><th>android:searchMode</th>
707 *         <td>If provided and non-zero, sets additional modes for control of the search
708 *             presentation.  The following mode bits are defined:
709 *             <table border="2" align="center" frame="hsides" rules="rows">
710 *                 <tbody>
711 *                 <tr><th>showSearchLabelAsBadge</th>
712 *                     <td>If set, this flag enables the display of the search target (label)
713 *                         within the search bar.  If this flag and showSearchIconAsBadge
714 *                         (see below) are both not set, no badge will be shown.</td>
715 *                 </tr>
716 *                 <tr><th>showSearchIconAsBadge</th>
717 *                     <td>If set, this flag enables the display of the search target (icon) within
718 *                         the search bar.  If this flag and showSearchLabelAsBadge
719 *                         (see above) are both not set, no badge will be shown.  If both flags
720 *                         are set, showSearchIconAsBadge has precedence and the icon will be
721 *                         shown.</td>
722 *                 </tr>
723 *                 <tr><th>queryRewriteFromData</th>
724 *                     <td>If set, this flag causes the suggestion column SUGGEST_COLUMN_INTENT_DATA
725 *                         to be considered as the text for suggestion query rewriting.  This should
726 *                         only be used when the values in SUGGEST_COLUMN_INTENT_DATA are suitable
727 *                         for user inspection and editing - typically, HTTP/HTTPS Uri's.</td>
728 *                 </tr>
729 *                 <tr><th>queryRewriteFromText</th>
730 *                     <td>If set, this flag causes the suggestion column SUGGEST_COLUMN_TEXT_1 to
731 *                         be considered as the text for suggestion query rewriting.  This should
732 *                         be used for suggestions in which no query text is provided and the
733 *                         SUGGEST_COLUMN_INTENT_DATA values are not suitable for user inspection
734 *                         and editing.</td>
735 *                 </tr>
736 *                 </tbody>
737 *            </table></td>
738 *         <td align="center">No</td>
739 *     </tr>
740 *
741 *     </tbody>
742 * </table>
743 *
744 * <p><b>Styleable Resources in your Metadata.</b>  It's possible to provide alternate strings
745 * for your searchable application, in order to provide localization and/or to better visual
746 * presentation on different device configurations.  Each searchable activity has a single XML
747 * metadata file, but any resource references can be replaced at runtime based on device
748 * configuration, language setting, and other system inputs.
749 *
750 * <p>A concrete example is the "hint" text you supply using the android:searchHint attribute.
751 * In portrait mode you'll have less screen space and may need to provide a shorter string, but
752 * in landscape mode you can provide a longer, more descriptive hint.  To do this, you'll need to
753 * define two or more strings.xml files, in the following directories:
754 * <ul><li>.../res/values-land/strings.xml</li>
755 * <li>.../res/values-port/strings.xml</li>
756 * <li>.../res/values/strings.xml</li></ul>
757 *
758 * <p>For more complete documentation on this capability, see
759 * <a href="../../../devel/resources-i18n.html#AlternateResources">Resources and
760 * Internationalization: Supporting Alternate Resources for Alternate Languages and Configurations
761 * </a>.
762 *
763 * <p><b>Metadata for non-searchable activities.</b>  Activities which are part of a searchable
764 * application, but don't implement search itself, require a bit of "glue" in order to cause
765 * them to invoke search using your searchable activity as their primary context.  If this is not
766 * provided, then searches from these activities will use the system default search context.
767 *
768 * <p>The simplest way to specify this is to add a <i>search reference</i> element to the
769 * application entry in the <a href="../../../devel/bblocks-manifest.html">manifest</a> file.
770 * The value of this reference can be either of:
771 * <ul><li>The name of your searchable activity.
772 * It is typically prefixed by '.' to indicate that it's in the same package.</li>
773 * <li>A "*" indicates that the system may select a default searchable activity, in which
774 * case it will typically select web-based search.</li>
775 * </ul>
776 *
777 * <p>Here is a snippet showing the necessary addition to the manifest entry for your
778 * non-searchable activities.
779 * <pre class="prettyprint">
780 *        &lt;application&gt;
781 *            &lt;meta-data android:name="android.app.default_searchable"
782 *                       android:value=".MySearchActivity" /&gt;
783 *
784 *            &lt;!-- followed by activities, providers, etc... --&gt;
785 *        &lt;/application&gt;</pre>
786 *
787 * <p>You can also specify android.app.default_searchable on a per-activity basis, by including
788 * the meta-data element (as shown above) in one or more activity sections.  If found, these will
789 * override the reference in the application section.  The only reason to configure your application
790 * this way would be if you wish to partition it into separate sections with different search
791 * behaviors;  Otherwise this configuration is not recommended.
792 *
793 * <p><b>Additional Metadata for search suggestions.</b>  If you have defined a content provider
794 * to generate search suggestions, you'll need to publish it to the system, and you'll need to
795 * provide a bit of additional XML metadata in order to configure communications with it.
796 *
797 * <p>First, in your <a href="../../../devel/bblocks-manifest.html">manifest</a>, you'll add the
798 * following lines.
799 * <pre class="prettyprint">
800 *        &lt;!-- Content provider for search suggestions --&gt;
801 *        &lt;provider android:name="YourSuggestionProviderClass"
802 *                android:authorities="your.suggestion.authority" /&gt;</pre>
803 *
804 * <p>Next, you'll add a few lines to your XML metadata file, as shown:
805 * <pre class="prettyprint">
806 *     &lt;!-- Required attribute for any suggestions provider --&gt;
807 *     android:searchSuggestAuthority="your.suggestion.authority"
808 *
809 *     &lt;!-- Optional attribute for configuring queries --&gt;
810 *     android:searchSuggestSelection="field =?"
811 *
812 *     &lt;!-- Optional attributes for configuring intent construction --&gt;
813 *     android:searchSuggestIntentAction="intent action string"
814 *     android:searchSuggestIntentData="intent data Uri" /&gt;</pre>
815 *
816 * <p>Elements of search metadata that support suggestions:
817 * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
818 *
819 *     <thead>
820 *     <tr><th>Attribute</th> <th>Description</th> <th>Required?</th></tr>
821 *     </thead>
822 *
823 *     <tbody>
824 *     <tr><th>android:searchSuggestAuthority</th>
825 *         <td>This value must match the authority string provided in the <i>provider</i> section
826 *             of your <a href="../../../devel/bblocks-manifest.html">manifest</a>.</td>
827 *         <td align="center">Yes</td>
828 *     </tr>
829 *
830 *     <tr><th>android:searchSuggestPath</th>
831 *         <td>If provided, this will be inserted in the suggestions query Uri, after the authority
832 *             you have provide but before the standard suggestions path.  This is only required if
833 *             you have a single content provider issuing different types of suggestions (e.g. for
834 *             different data types) and you need a way to disambiguate the suggestions queries
835 *             when they are received.</td>
836 *         <td align="center">No</td>
837 *     </tr>
838 *
839 *     <tr><th>android:searchSuggestSelection</th>
840 *         <td>If provided, this value will be passed into your query function as the
841 *             <i>selection</i> parameter.  Typically this will be a WHERE clause for your database,
842 *             and will contain a single question mark, which represents the actual query string
843 *             that has been typed by the user.  However, you can also use any non-null value
844 *             to simply trigger the delivery of the query text (via selection arguments), and then
845 *             use the query text in any way appropriate for your provider (ignoring the actual
846 *             text of the selection parameter.)</td>
847 *         <td align="center">No</td>
848 *     </tr>
849 *
850 *     <tr><th>android:searchSuggestIntentAction</th>
851 *         <td>If provided, and not overridden by the selected suggestion, this value will be
852 *             placed in the action field of the {@link android.content.Intent Intent} when the
853 *             user clicks a suggestion.</td>
854 *         <td align="center">No</td>
855 *
856 *     <tr><th>android:searchSuggestIntentData</th>
857 *         <td>If provided, and not overridden by the selected suggestion, this value will be
858 *             placed in the data field of the {@link android.content.Intent Intent} when the user
859 *             clicks a suggestion.</td>
860 *         <td align="center">No</td>
861 *     </tr>
862 *
863 *     </tbody>
864 * </table>
865 *
866 * <p><b>Additional Metadata for search action keys.</b>  For each action key that you would like to
867 * define, you'll need to add an additional element defining that key, and using the attributes
868 * discussed in <a href="#ActionKeys">Action Keys</a>.  A simple example is shown here:
869 *
870 * <pre class="prettyprint">&lt;actionkey
871 *     android:keycode="KEYCODE_CALL"
872 *     android:queryActionMsg="call"
873 *     android:suggestActionMsg="call"
874 *     android:suggestActionMsgColumn="call_column" /&gt;</pre>
875 *
876 * <p>Elements of search metadata that support search action keys.  Note that although each of the
877 * action message elements are marked as <i>optional</i>, at least one must be present for the
878 * action key to have any effect.
879 *
880 * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
881 *
882 *     <thead>
883 *     <tr><th>Attribute</th> <th>Description</th> <th>Required?</th></tr>
884 *     </thead>
885 *
886 *     <tbody>
887 *     <tr><th>android:keycode</th>
888 *         <td>This attribute denotes the action key you wish to respond to.  Note that not
889 *             all action keys are actually supported using this mechanism, as many of them are
890 *             used for typing, navigation, or system functions.  This will be added to the
891 *             {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to
892 *             your searchable activity.  To examine the key code, use
893 *             {@link android.content.Intent#getIntExtra getIntExtra(SearchManager.ACTION_KEY)}.
894 *             <p>Note, in addition to the keycode, you must also provide one or more of the action
895 *             specifier attributes.</td>
896 *         <td align="center">Yes</td>
897 *     </tr>
898 *
899 *     <tr><th>android:queryActionMsg</th>
900 *         <td>If you wish to handle an action key during normal search query entry, you
901 *          must define an action string here.  This will be added to the
902 *          {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to your
903 *          searchable activity.  To examine the string, use
904 *          {@link android.content.Intent#getStringExtra
905 *          getStringExtra(SearchManager.ACTION_MSG)}.</td>
906 *         <td align="center">No</td>
907 *     </tr>
908 *
909 *     <tr><th>android:suggestActionMsg</th>
910 *         <td>If you wish to handle an action key while a suggestion is being displayed <i>and
911 *             selected</i>, there are two ways to handle this.  If <i>all</i> of your suggestions
912 *             can handle the action key, you can simply define the action message using this
913 *             attribute.  This will be added to the
914 *             {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to
915 *             your searchable activity.  To examine the string, use
916 *             {@link android.content.Intent#getStringExtra
917 *             getStringExtra(SearchManager.ACTION_MSG)}.</td>
918 *         <td align="center">No</td>
919 *     </tr>
920 *
921 *     <tr><th>android:suggestActionMsgColumn</th>
922 *         <td>If you wish to handle an action key while a suggestion is being displayed <i>and
923 *             selected</i>, but you do not wish to enable this action key for every suggestion,
924 *             then you can use this attribute to control it on a suggestion-by-suggestion basis.
925 *             First, you must define a column (and name it here) where your suggestions will
926 *             include the action string.  Then, in your content provider, you must provide this
927 *             column, and when desired, provide data in this column.
928 *             The search manager will look at your suggestion cursor, using the string
929 *             provided here in order to select a column, and will use that to select a string from
930 *             the cursor.  That string will be added to the
931 *             {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to
932 *             your searchable activity.  To examine the string, use
933 *             {@link android.content.Intent#getStringExtra
934 *             getStringExtra(SearchManager.ACTION_MSG)}.  <i>If the data does not exist for the
935 *             selection suggestion, the action key will be ignored.</i></td>
936 *         <td align="center">No</td>
937 *     </tr>
938 *
939 *     </tbody>
940 * </table>
941 *
942 * <a name="PassingSearchContext"></a>
943 * <h3>Passing Search Context</h3>
944 *
945 * <p>In order to improve search experience, an application may wish to specify
946 * additional data along with the search, such as local history or context.  For
947 * example, a maps search would be improved by including the current location.
948 * In order to simplify the structure of your activities, this can be done using
949 * the search manager.
950 *
951 * <p>Any data can be provided at the time the search is launched, as long as it
952 * can be stored in a {@link android.os.Bundle Bundle} object.
953 *
954 * <p>To pass application data into the Search Manager, you'll need to override
955 * {@link android.app.Activity#onSearchRequested onSearchRequested} as follows:
956 *
957 * <pre class="prettyprint">
958 * &#64;Override
959 * public boolean onSearchRequested() {
960 *     Bundle appData = new Bundle();
961 *     appData.put...();
962 *     appData.put...();
963 *     startSearch(null, false, appData);
964 *     return true;
965 * }</pre>
966 *
967 * <p>To receive application data from the Search Manager, you'll extract it from
968 * the {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH}
969 * {@link android.content.Intent Intent} as follows:
970 *
971 * <pre class="prettyprint">
972 * final Bundle appData = queryIntent.getBundleExtra(SearchManager.APP_DATA);
973 * if (appData != null) {
974 *     appData.get...();
975 *     appData.get...();
976 * }</pre>
977 */
978public class SearchManager
979        implements DialogInterface.OnDismissListener, DialogInterface.OnCancelListener
980{
981    /**
982     * This is a shortcut definition for the default menu key to use for invoking search.
983     *
984     * See Menu.Item.setAlphabeticShortcut() for more information.
985     */
986    public final static char MENU_KEY = 's';
987
988    /**
989     * This is a shortcut definition for the default menu key to use for invoking search.
990     *
991     * See Menu.Item.setAlphabeticShortcut() for more information.
992     */
993    public final static int MENU_KEYCODE = KeyEvent.KEYCODE_S;
994
995    /**
996     * Intent extra data key: Use this key with
997     * {@link android.content.Intent#getStringExtra
998     *  content.Intent.getStringExtra()}
999     * to obtain the query string from Intent.ACTION_SEARCH.
1000     */
1001    public final static String QUERY = "query";
1002
1003    /**
1004     * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
1005     * {@link android.content.Intent#getBundleExtra
1006     *  content.Intent.getBundleExtra()}
1007     * to obtain any additional app-specific data that was inserted by the
1008     * activity that launched the search.
1009     */
1010    public final static String APP_DATA = "app_data";
1011
1012    /**
1013     * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
1014     * {@link android.content.Intent#getIntExtra content.Intent.getIntExtra()}
1015     * to obtain the keycode that the user used to trigger this query.  It will be zero if the
1016     * user simply pressed the "GO" button on the search UI.  This is primarily used in conjunction
1017     * with the keycode attribute in the actionkey element of your searchable.xml configuration
1018     * file.
1019     */
1020    public final static String ACTION_KEY = "action_key";
1021
1022    /**
1023     * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
1024     * {@link android.content.Intent#getStringExtra content.Intent.getStringExtra()}
1025     * to obtain the action message that was defined for a particular search action key and/or
1026     * suggestion.  It will be null if the search was launched by typing "enter", touched the the
1027     * "GO" button, or other means not involving any action key.
1028     */
1029    public final static String ACTION_MSG = "action_msg";
1030
1031    /**
1032     * Uri path for queried suggestions data.  This is the path that the search manager
1033     * will use when querying your content provider for suggestions data based on user input
1034     * (e.g. looking for partial matches).
1035     * Typically you'll use this with a URI matcher.
1036     */
1037    public final static String SUGGEST_URI_PATH_QUERY = "search_suggest_query";
1038
1039    /**
1040     * MIME type for suggestions data.  You'll use this in your suggestions content provider
1041     * in the getType() function.
1042     */
1043    public final static String SUGGEST_MIME_TYPE =
1044                                  "vnd.android.cursor.dir/vnd.android.search.suggest";
1045
1046    /**
1047     * Column name for suggestions cursor.  <i>Unused - can be null or column can be omitted.</i>
1048     */
1049    public final static String SUGGEST_COLUMN_FORMAT = "suggest_format";
1050    /**
1051     * Column name for suggestions cursor.  <i>Required.</i>  This is the primary line of text that
1052     * will be presented to the user as the suggestion.
1053     */
1054    public final static String SUGGEST_COLUMN_TEXT_1 = "suggest_text_1";
1055    /**
1056     * Column name for suggestions cursor.  <i>Optional.</i>  If your cursor includes this column,
1057     *  then all suggestions will be provided in a two-line format.  The second line of text is in
1058     *  a much smaller appearance.
1059     */
1060    public final static String SUGGEST_COLUMN_TEXT_2 = "suggest_text_2";
1061    /**
1062     * Column name for suggestions cursor.  <i>Optional.</i>  If your cursor includes this column,
1063     *  then all suggestions will be provided in format that includes space for two small icons,
1064     *  one at the left and one at the right of each suggestion.  The data in the column must
1065     *  be a a resource ID for the icon you wish to have displayed.  If you include this column,
1066     *  you must also include {@link #SUGGEST_COLUMN_ICON_2}.
1067     */
1068    public final static String SUGGEST_COLUMN_ICON_1 = "suggest_icon_1";
1069    /**
1070     * Column name for suggestions cursor.  <i>Optional.</i>  If your cursor includes this column,
1071     *  then all suggestions will be provided in format that includes space for two small icons,
1072     *  one at the left and one at the right of each suggestion.  The data in the column must
1073     *  be a a resource ID for the icon you wish to have displayed.  If you include this column,
1074     *  you must also include {@link #SUGGEST_COLUMN_ICON_1}.
1075     */
1076    public final static String SUGGEST_COLUMN_ICON_2 = "suggest_icon_2";
1077    /**
1078     * Column name for suggestions cursor.  <i>Optional.</i>  If this column exists <i>and</i>
1079     * this element exists at the given row, this is the action that will be used when
1080     * forming the suggestion's intent.  If the element is not provided, the action will be taken
1081     * from the android:searchSuggestIntentAction field in your XML metadata.  <i>At least one of
1082     * these must be present for the suggestion to generate an intent.</i>  Note:  If your action is
1083     * the same for all suggestions, it is more efficient to specify it using XML metadata and omit
1084     * it from the cursor.
1085     */
1086    public final static String SUGGEST_COLUMN_INTENT_ACTION = "suggest_intent_action";
1087    /**
1088     * Column name for suggestions cursor.  <i>Optional.</i>  If this column exists <i>and</i>
1089     * this element exists at the given row, this is the data that will be used when
1090     * forming the suggestion's intent.  If the element is not provided, the data will be taken
1091     * from the android:searchSuggestIntentData field in your XML metadata.  If neither source
1092     * is provided, the Intent's data field will be null.  Note:  If your data is
1093     * the same for all suggestions, or can be described using a constant part and a specific ID,
1094     * it is more efficient to specify it using XML metadata and omit it from the cursor.
1095     */
1096    public final static String SUGGEST_COLUMN_INTENT_DATA = "suggest_intent_data";
1097    /**
1098     * Column name for suggestions cursor.  <i>Optional.</i>  If this column exists <i>and</i>
1099     * this element exists at the given row, then "/" and this value will be appended to the data
1100     * field in the Intent.  This should only be used if the data field has already been set to an
1101     * appropriate base string.
1102     */
1103    public final static String SUGGEST_COLUMN_INTENT_DATA_ID = "suggest_intent_data_id";
1104    /**
1105     * Column name for suggestions cursor.  <i>Required if action is
1106     * {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH}, optional otherwise.</i>  If this
1107     * column exists <i>and</i> this element exists at the given row, this is the data that will be
1108     * used when forming the suggestion's query.
1109     */
1110    public final static String SUGGEST_COLUMN_QUERY = "suggest_intent_query";
1111
1112
1113    private final Context mContext;
1114    private final Handler mHandler;
1115
1116    private SearchDialog mSearchDialog;
1117
1118    private OnDismissListener mDismissListener = null;
1119    private OnCancelListener mCancelListener = null;
1120
1121    /*package*/ SearchManager(Context context, Handler handler)  {
1122        mContext = context;
1123        mHandler = handler;
1124    }
1125    private static ISearchManager mService;
1126
1127    static {
1128        mService = ISearchManager.Stub.asInterface(
1129                    ServiceManager.getService(Context.SEARCH_SERVICE));
1130    }
1131
1132    /**
1133     * Launch search UI.
1134     *
1135     * <p>The search manager will open a search widget in an overlapping
1136     * window, and the underlying activity may be obscured.  The search
1137     * entry state will remain in effect until one of the following events:
1138     * <ul>
1139     * <li>The user completes the search.  In most cases this will launch
1140     * a search intent.</li>
1141     * <li>The user uses the back, home, or other keys to exit the search.</li>
1142     * <li>The application calls the {@link #stopSearch}
1143     * method, which will hide the search window and return focus to the
1144     * activity from which it was launched.</li>
1145     *
1146     * <p>Most applications will <i>not</i> use this interface to invoke search.
1147     * The primary method for invoking search is to call
1148     * {@link android.app.Activity#onSearchRequested Activity.onSearchRequested()} or
1149     * {@link android.app.Activity#startSearch Activity.startSearch()}.
1150     *
1151     * @param initialQuery A search string can be pre-entered here, but this
1152     * is typically null or empty.
1153     * @param selectInitialQuery If true, the intial query will be preselected, which means that
1154     * any further typing will replace it.  This is useful for cases where an entire pre-formed
1155     * query is being inserted.  If false, the selection point will be placed at the end of the
1156     * inserted query.  This is useful when the inserted query is text that the user entered,
1157     * and the user would expect to be able to keep typing.  <i>This parameter is only meaningful
1158     * if initialQuery is a non-empty string.</i>
1159     * @param launchActivity The ComponentName of the activity that has launched this search.
1160     * @param appSearchData An application can insert application-specific
1161     * context here, in order to improve quality or specificity of its own
1162     * searches.  This data will be returned with SEARCH intent(s).  Null if
1163     * no extra data is required.
1164     * @param globalSearch If false, this will only launch the search that has been specifically
1165     * defined by the application (which is usually defined as a local search).  If no default
1166     * search is defined in the current application or activity, no search will be launched.
1167     * If true, this will always launch a platform-global (e.g. web-based) search instead.
1168     *
1169     * @see android.app.Activity#onSearchRequested
1170     * @see #stopSearch
1171     */
1172    public void startSearch(String initialQuery,
1173                            boolean selectInitialQuery,
1174                            ComponentName launchActivity,
1175                            Bundle appSearchData,
1176                            boolean globalSearch) {
1177
1178        if (mSearchDialog == null) {
1179            mSearchDialog = new SearchDialog(mContext);
1180        }
1181
1182        // activate the search manager and start it up!
1183        mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
1184                globalSearch);
1185
1186        mSearchDialog.setOnCancelListener(this);
1187        mSearchDialog.setOnDismissListener(this);
1188    }
1189
1190    /**
1191     * Terminate search UI.
1192     *
1193     * <p>Typically the user will terminate the search UI by launching a
1194     * search or by canceling.  This function allows the underlying application
1195     * or activity to cancel the search prematurely (for any reason).
1196     *
1197     * <p>This function can be safely called at any time (even if no search is active.)
1198     *
1199     * @see #startSearch
1200     */
1201    public void stopSearch()  {
1202        if (mSearchDialog != null) {
1203            mSearchDialog.cancel();
1204        }
1205    }
1206
1207    /**
1208     * Determine if the Search UI is currently displayed.
1209     *
1210     * This is provided primarily for application test purposes.
1211     *
1212     * @return Returns true if the search UI is currently displayed.
1213     *
1214     * @hide
1215     */
1216    public boolean isVisible()  {
1217        if (mSearchDialog != null) {
1218            return mSearchDialog.isShowing();
1219        }
1220        return false;
1221    }
1222
1223    /**
1224     * See {@link #setOnDismissListener} for configuring your activity to monitor search UI state.
1225     */
1226    public interface OnDismissListener {
1227        /**
1228         * This method will be called when the search UI is dismissed. To make use if it, you must
1229         * implement this method in your activity, and call {@link #setOnDismissListener} to
1230         * register it.
1231         */
1232        public void onDismiss();
1233    }
1234
1235    /**
1236     * See {@link #setOnCancelListener} for configuring your activity to monitor search UI state.
1237     */
1238    public interface OnCancelListener {
1239        /**
1240         * This method will be called when the search UI is canceled. To make use if it, you must
1241         * implement this method in your activity, and call {@link #setOnCancelListener} to
1242         * register it.
1243         */
1244        public void onCancel();
1245    }
1246
1247    /**
1248     * Set or clear the callback that will be invoked whenever the search UI is dismissed.
1249     *
1250     * @param listener The {@link OnDismissListener} to use, or null.
1251     */
1252    public void setOnDismissListener(final OnDismissListener listener) {
1253        mDismissListener = listener;
1254    }
1255
1256    /**
1257     * The callback from the search dialog when dismissed
1258     * @hide
1259     */
1260    public void onDismiss(DialogInterface dialog) {
1261        if (dialog == mSearchDialog) {
1262            if (mDismissListener != null) {
1263                mDismissListener.onDismiss();
1264            }
1265        }
1266    }
1267
1268    /**
1269     * Set or clear the callback that will be invoked whenever the search UI is canceled.
1270     *
1271     * @param listener The {@link OnCancelListener} to use, or null.
1272     */
1273    public void setOnCancelListener(final OnCancelListener listener) {
1274        mCancelListener = listener;
1275    }
1276
1277
1278    /**
1279     * The callback from the search dialog when canceled
1280     * @hide
1281     */
1282    public void onCancel(DialogInterface dialog) {
1283        if (dialog == mSearchDialog) {
1284            if (mCancelListener != null) {
1285                mCancelListener.onCancel();
1286            }
1287        }
1288    }
1289
1290    /**
1291     * Save instance state so we can recreate after a rotation.
1292     *
1293     * @hide
1294     */
1295    void saveSearchDialog(Bundle outState, String key) {
1296        if (mSearchDialog != null && mSearchDialog.isShowing()) {
1297            Bundle searchDialogState = mSearchDialog.onSaveInstanceState();
1298            outState.putBundle(key, searchDialogState);
1299        }
1300    }
1301
1302    /**
1303     * Restore instance state after a rotation.
1304     *
1305     * @hide
1306     */
1307    void restoreSearchDialog(Bundle inState, String key) {
1308        Bundle searchDialogState = inState.getBundle(key);
1309        if (searchDialogState != null) {
1310            if (mSearchDialog == null) {
1311                mSearchDialog = new SearchDialog(mContext);
1312            }
1313            mSearchDialog.onRestoreInstanceState(searchDialogState);
1314        }
1315    }
1316
1317    /**
1318     * Hook for updating layout on a rotation
1319     *
1320     * @hide
1321     */
1322    void onConfigurationChanged(Configuration newConfig) {
1323        if (mSearchDialog != null && mSearchDialog.isShowing()) {
1324            mSearchDialog.onConfigurationChanged(newConfig);
1325        }
1326    }
1327
1328}
1329