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