OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / docs / html / guide / topics / search / search-dialog.jd
1 page.title=Using the Android Search Dialog
2 parent.title=Search
3 parent.link=index.html
4 @jd:body
5
6 <div id="qv-wrapper">
7 <div id="qv">
8 <h2>In this document</h2>
9 <ol>
10 <li><a href="#TheBasics">The Basics</a></li>
11 <li><a href="#SearchableConfiguration">Creating a Searchable Configuration</a></li>
12 <li><a href="#SearchableActivity">Creating a Searchable Activity</a>
13   <ol>
14     <li><a href="#DeclaringSearchableActivity">Declaring a searchable Activity</a></li>
15     <li><a href="#PerformingSearch">Performing a search</a></li>
16   </ol>
17 </li>
18 <li><a href="#InvokingTheSearchDialog">Invoking the Search Dialog</a>
19   <ol>
20     <li><a href="#LifeCycle">The impact of the search dialog on your Activity life-cycle</a></li>
21   </ol>
22 </li>
23 <li><a href="#SearchContextData">Passing Search Context Data</a></li>
24 <li><a href="#VoiceSearch">Adding Voice Search</a></li>
25 </ol>
26
27 <h2>Key classes</h2>
28 <ol>
29 <li>{@link android.app.SearchManager}</li>
30 </ol>
31
32 <h2>Related samples</h2>
33 <ol>
34 <li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable
35 Dictionary</a></li>
36 </ol>
37
38 <h2>Downloads</h2>
39 <ol>
40 <li><a href="{@docRoot}shareables/search_icons.zip">search_icons.zip</a></li>
41 </ol>
42
43 <h2>See also</h2>
44 <ol>
45 <li><a href="adding-recent-query-suggestions.html">Adding Recent Query Suggestions</a></li>
46 <li><a href="adding-custom-suggestions.html">Adding Custom Suggestions</a></li>
47 <li><a href="searchable-config.html">Searchable Configuration</a></li>
48 </ol>
49
50 </div>
51 </div>
52
53 <p>When you want to implement search in your application, the last thing you should have to worry
54 about is where to put the search box. When you implement search with the Android search framework,
55 you don't have to. When the user invokes search, a search dialog appears at the top of the screen
56 with your application icon to the left of the search box. When the user executes the search, your
57 application receives the query so it can search your application's data. An example of the search
58 dialog is shown in figure 1.</p>
59
60 <p>This guide shows you how to set up your application to provide search in the search
61 dialog. When you use the search dialog, you provide a standardized search
62 experience and can add features such as voice search and search suggestions.</p>
63
64
65 <h2 id="TheBasics">The Basics</h2>
66
67 <div class="figure" style="width:250px">
68 <img src="{@docRoot}images/search/search-ui.png" alt="" height="417" />
69 <p class="img-caption"><strong>Figure 1.</strong> Screenshot of an application's search dialog.</p>
70 </div>
71
72 <p>The Android search framework manages the search dialog for your application. You never need
73 to draw it or worry about where it is, and your Activity is not interrupted when the search dialog
74 appears. The Search Manager ({@link android.app.SearchManager}) is the component that does this work
75 for you. It manages the life of the search dialog and sends your application the user's search
76 query.</p>
77
78 <p>When the user executes a search, the Search Manager creates an {@link android.content.Intent} to
79 pass the search query to the Activity that you've declared to handle searches. Basically, all you
80 need is an Activity that receives the search Intent, performs the search, and presents the results.
81 Specifically, you need the following:</p>
82
83 <dl>
84   <dt>A searchable configuration</dt>
85   <dd>An XML file that configures the search dialog and includes settings for features such as voice
86 search, search suggestion, and the hint text.</dd>
87   <dt>A searchable Activity</dt>
88   <dd>The {@link android.app.Activity} that receives the search query, then searches your data and
89 displays the search results.</dd>
90   <dt>A mechanism by which the user can invoke search</dt>
91   <dd>The device search key invokes the search dialog, by default. However, a dedicated search key
92 is not guaranteed on all devices, so provide another means by which the user can invoke a search,
93 such as a search button in the Options Menu or elsewhere in the Activity UI.</dd>
94 </dl>
95
96
97
98 <h2 id="SearchableConfiguration">Creating a Searchable Configuration</h2>
99
100 <p>The searchable configuration is an XML file that defines several settings for the search
101 dialog in your application. This file is traditionally named {@code searchable.xml} and must be
102 saved in the {@code res/xml/} project directory.</p>
103
104 <p>The file must consist of the {@code &lt;searchable&gt;} element as the root node and specify one
105 or more attributes that configure your search dialog. For example:</p>
106
107 <pre>
108 &lt;?xml version="1.0" encoding="utf-8"?>
109 &lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
110     android:label="@string/app_label"
111     android:hint="@string/search_hint" >
112 &lt;/searchable>
113 </pre>
114
115 <p>The {@code android:label} attribute is the only required attribute and points to a string
116 resource, which should be the same as the application name. This label isn't actually visible to the
117 user until you enable suggestions for Quick Search Box, at which point, this label is visible in the
118 list of Searchable items in the system Settings.</p>
119
120 <p>Though it's not required, we recommend that you always include the {@code android:hint}
121 attribute, which provides a hint string in the search dialog's text box before the user
122 enters their query. The hint is important because it provides important clues to users about what
123 they can search.</p>
124
125 <p class="note"><strong>Tip:</strong> For consistency among other
126 Android applications, you should format the string for {@code android:hint} as "Search
127 <em>&lt;content-or-product&gt;</em>". For example, "Search songs and artists" or "Search
128 YouTube".</p>
129
130 <p>The {@code &lt;searchable&gt;} element accepts several other attributes. Most attributes apply
131 only when configuring features such as search suggestions and voice search.</p>
132
133 <p>For more details about the searchable configuration file, see the <a
134 href="{@docRoot}guide/topics/search/searchable-config.html">Searchable Configuration</a>
135 reference.</p>
136
137
138
139 <h2 id="SearchableActivity">Creating a Searchable Activity</h2>
140
141 <p>When the user executes a search from the search dialog, the Search Manager takes the query
142 and sends it to your searchable {@link android.app.Activity} in the {@link
143 android.content.Intent#ACTION_SEARCH} {@link android.content.Intent}. Your searchable Activity
144 then searches your data using the query and presents the results to the user.</p>
145
146 <p>In order for the Search Manager to know where to deliver the search query, you must declare your
147 searchable Activity in the Android manifest file.</p>
148
149
150 <h3 id="DeclaringSearchableActivity">Declaring a searchable Activity</h3>
151
152 <p>If you don't have one already, create an {@link android.app.Activity} that performs
153 searches and present search results. To set up this Activity as your searchable Activity:</p>
154 <ol>
155   <li>Declare the Activity to accept the {@link android.content.Intent#ACTION_SEARCH} {@link
156 android.content.Intent}, in an <a
157 href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a>
158 element.</li>
159   <li>Apply the searchable configuration, in a <a
160 href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code &lt;meta-data&gt;}</a>
161 element.</li>
162 </ol>
163
164 <p>For example:</p>
165
166 <pre>
167 &lt;application ... >
168     &lt;activity android:name=".MySearchableActivity" >
169         &lt;intent-filter>
170             &lt;action android:name="android.intent.action.SEARCH" />
171         &lt;/intent-filter>
172         &lt;meta-data android:name="android.app.searchable"
173                    android:resource="@xml/searchable"/>
174     &lt;/activity>
175     ...
176 &lt;/application>
177 </pre>
178
179 <p>The {@code &lt;meta-data&gt;} element must include the {@code android:name} attribute with a
180 value of {@code "android.app.searchable"} and the {@code android:resource} attribute with a
181 reference to the searchable configuration file (in this example, it
182 refers to the {@code res/xml/searchable.xml} file).</p>
183
184 <p class="note"><strong>Note:</strong> The {@code &lt;intent-filter&gt;} does not need a <a
185 href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category&gt;}</a> with the
186 {@code DEFAULT} value, because the Search Manager delivers the {@link
187 android.content.Intent#ACTION_SEARCH} Intent explicitly to your searchable Activity by name.</p>
188
189 <p>The search dialog is not, by default, available from every Activity of your
190 application. Rather, the search dialog is presented to users only when they
191 invoke search from a searchable context of your application. A searchable context is any Activity
192 for which you have
193 declared searchable meta-data in the manifest file. For example, the searchable Activity itself
194 (declared in the manifest snippet above) is
195 a searchable context because it includes meta-data that defines the
196 searchable configuration. Any other Activity in your application is not a searchable context, by
197 default, and thus, does not reveal the search dialog. However, you probably do want the search
198 dialog available from your other activities (and to launch the searchable Activity when the user
199 executes a search). You can do exactly that.</p>
200
201 <p>If you want all of your activities to provide the search dialog, add another {@code
202 &lt;meta-data&gt;} element inside the {@code
203 &lt;application&gt;} element. Use this element to declare the existing searchable Activity as the
204 default searchable Activity. For example:</p>
205
206 <pre>
207 &lt;application ... >
208     &lt;activity android:name=".MySearchableActivity" >
209         &lt;intent-filter>
210             &lt;action android:name="android.intent.action.SEARCH" />
211         &lt;/intent-filter>
212         &lt;meta-data android:name="android.app.searchable"
213                    android:resource="@xml/searchable"/>
214     &lt;/activity>
215     &lt;activity android:name=".AnotherActivity" ... >
216     &lt;/activity>
217     &lt;!-- declare the default searchable Activity for the whole app --&gt;
218     <b>&lt;meta-data android:name="android.app.default_searchable"
219                android:value=".MySearchableActivity" /&gt;</b>
220     ...
221 &lt;/application>
222 </pre>
223
224 <p>The {@code &lt;meta-data&gt;} element with the {@code android:name} attribute value of
225 {@code "android.app.default_searchable"} specifies a default searchable Activity for the context in
226 which it is placed (which, in this case, is the entire application). The searchable Activity to
227 use is specified with the {@code android:value} attribute. All other activities in the
228 application, such as {@code AnotherActivity}, are now considered a searchable context and can invoke
229 the search dialog. When a search is executed, {@code MySearchableActivity} is launched to handle
230 the search query.</p>
231
232 <p>You can also control which activities provide search at a more granular level.
233 To specify only an individual Activity as a searchable context, place the {@code
234 &lt;meta-data&gt;} with the {@code
235 "android.app.default_searchable"} name inside the respective {@code &lt;activity&gt;}
236 element (rather than inside the {@code &lt;application&gt;} element). While uncommon, you
237 can also create more than one searchable Activity and provide each one in different contexts of your
238 application, either by declaring a different searchable Activity in each {@code &lt;activity&gt;}
239 element, or by declaring a default searchable Activity for the entire application and then
240 overriding it with a {@code &lt;meta-data&gt;} element inside certain activities. (You might do
241 this if you want to search different sets of data that cannot be handled by the same
242 searchable Activity, depending on the currently open Activity.)</p>
243
244
245 <h3 id="PerformingSearch">Performing a search</h3>
246
247 <p>Once you have declared your searchable Activity, performing a search for the user involves
248 three steps:</p>
249 <ol>
250   <li><a href="#ReceivingTheQuery">Receiving the query</a></li>
251   <li><a href="#SearchingYourData">Searching your data</a></li>
252   <li><a href="#PresentingTheResults">Presenting the results</a></li>
253 </ol>
254
255 <p>Traditionally, your search results should be presented in a {@link android.widget.ListView}, so
256 you might want your searchable Activity to extend {@link android.app.ListActivity}, which
257 provides easy access to {@link android.widget.ListView} APIs. (See the <a
258 href="{@docRoot}resources/tutorials/views/hello-listview.html">List View Tutorial</a> for a simple
259 {@link android.app.ListActivity} sample.)</p>
260
261
262 <h4 id="ReceivingTheQuery">Receiving the query</h4>
263
264 <p>When a user executes a search from the search dialog, the Search Manager sends the {@link
265 android.content.Intent#ACTION_SEARCH} {@link android.content.Intent} to your searchable Activity.
266 This Intent carries the search query in the
267 {@link android.app.SearchManager#QUERY QUERY} string extra. You must check for
268 this Intent when the Activity starts and extract the string. For example, here's how you can get the
269 query when your Activity starts:</p>
270
271 <pre>
272 &#64;Override
273 public void onCreate(Bundle savedInstanceState) {
274     super.onCreate(savedInstanceState);
275     setContentView(R.layout.search);
276
277     Intent intent = getIntent();
278
279     if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
280       String query = intent.getStringExtra(SearchManager.QUERY);
281       doMySearch(query);
282     }
283 }
284 </pre>
285
286 <p>The {@link android.app.SearchManager#QUERY QUERY} string is always included with
287 the {@link android.content.Intent#ACTION_SEARCH} Intent. In this example, the query is
288 retrieved and passed to a local {@code doMySearch()} method where the actual search operation
289 is done.</p>
290
291
292 <h4 id="SearchingYourData">Searching your data</h4>
293
294 <p>The process of storing and searching your data is unique to your application.
295 You can store and search your data in many ways, but this guide does not show you how to store your
296 data and search it. Storing and searching your data is something you should carefully consider in
297 terms of your needs and your data. However, here are some tips you might be able to apply:</p>
298
299   <ul>
300     <li>If your data is stored in a SQLite database on the device, performing a full-text search
301 (using FTS3, rather than a LIKE query) can provide a more robust search across text data and can
302 produce results significantly faster. See <a href="http://sqlite.org/fts3.html">sqlite.org</a>
303 for information about FTS3 and the {@link android.database.sqlite.SQLiteDatabase} class for
304 information about SQLite on Android. Also look at the <a
305 href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable Dictionary</a> sample
306 application to see a complete SQLite implementation that performs searches with FTS3.</li>
307     <li>If your data is stored online, then the perceived search performance might be
308 inhibited by the user's data connection. You might want to display a spinning progress wheel until
309 your search returns. See {@link android.net} for a reference of network APIs and <a
310 href="{@docRoot}guide/topics/ui/dialogs.html#ProgressDialog">Creating a Progress Dialog</a> to see
311 how you can display a progress wheel.</li>
312   </ul>
313
314
315 <div class="sidebox-wrapper">
316 <div class="sidebox">
317 <h2>About Adapters</h2>
318 <p>An Adapter binds individual items from a set of data into individual {@link
319 android.view.View} objects. When the Adapter
320 is applied to a {@link android.widget.ListView}, the Views are injected as individual items of the
321 list. {@link
322 android.widget.Adapter} is simply an interface, so implementations such as {@link
323 android.widget.CursorAdapter} (for binding data from a {@link android.database.Cursor}) are needed.
324 If none of the existing implementations work for your data, then you should implement your own from
325 {@link android.widget.BaseAdapter}. Install the SDK Samples package for API Level 4 to see the
326 original version of the Searchable Dictionary, which creates a custom BaseAdapter.</p>
327 </div>
328 </div>
329
330 <p>Regardless of where your data lives and how you search it, we recommend that you return search
331 results to your searchable Activity with an {@link android.widget.Adapter}. This way, you can easily
332 present all the search results in a {@link android.widget.ListView}. If your data comes from a
333 SQLite database query, then you can apply your results to a {@link android.widget.ListView}
334 using a {@link android.widget.CursorAdapter}. If your data comes in some other type of format, then
335 you can create an extension of the {@link android.widget.BaseAdapter}.</p>
336
337 <h4 id="PresentingTheResults">Presenting the results</h4>
338
339 <p>Presenting your search results is mostly a UI detail that is not handled by the search APIs.
340 However, one option is to create your searchable Activity to extend {@link
341 android.app.ListActivity} and call {@link
342 android.app.ListActivity#setListAdapter(ListAdapter)}, passing it an {@link
343 android.widget.Adapter} that is bound to your data. This injects all the
344 results into the Activity {@link android.widget.ListView}.</p>
345
346 <p>For more help presenting your results, see the {@link android.app.ListActivity}
347 documentation.</p>
348
349 <p>Also see the <a
350 href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable Dictionary</a> sample
351 for an a complete demonstration of how to search an SQLite database and use an
352 {@link android.widget.Adapter} to provide results in a {@link android.widget.ListView}.</p>
353
354
355
356 <h2 id="InvokingTheSearchDialog">Invoking the Search Dialog</h2>
357
358 <p>Once you have a searchable Activity, invoking the search dialog is easy. Many Android
359 devices provide a dedicated SEARCH key, which reveals the search dialog when the user presses it
360 from a searchable context of your application. However, you should not assume that a SEARCH
361 key is available on the user's device and should always provide a search button in your UI that
362 invokes search.</p>
363
364 <p>To invoke search from your Activity, call {@link android.app.Activity#onSearchRequested()}.</p>
365
366 <p>For instance, you should provide a menu item in your <a
367 href="{@docRoot}guide/topics/ui/menus.html#options-menu">Options Menu</a> or a button in your UI to
368 invoke search with this method. The <a
369 href="{@docRoot}shareables/search_icons.zip">search_icons.zip</a> file includes icons for
370 medium and high density screens, which you can use for your search menu item or button (low density
371 screens automatically scale-down the hdpi image by one half). </p>
372
373 <!-- ... maybe this should go into the Creating Menus document ....
374 <p>If you chose to provide a shortcut key for the menu item,  using {@link
375 android.view.MenuItem#setAlphabeticShortcut(char)}, then SearchManager.MENU_KEY is the recommended
376 key character, representing the default search key.</p>
377 -->
378
379 <p>You can also enable "type-to-search" functionality, which reveals the search dialog when the
380 user starts typing on the keyboard and the keystrokes are inserted into the search dialog. You can
381 enable type-to-search in your Activity by calling
382 {@link android.app.Activity#setDefaultKeyMode(int) setDefaultKeyMode}({@link
383 android.app.Activity#DEFAULT_KEYS_SEARCH_LOCAL}) during your Activity's
384 {@link android.app.Activity#onCreate(Bundle) onCreate()} method.</p>
385
386
387 <h3 id="LifeCycle">The impact of the search dialog on your Activity lifecycle</h3>
388
389 <p>The search dialog is a {@link android.app.Dialog} that floats at the top of the
390 screen. It does not cause any change in the Activity stack, so when the search dialog appears, no
391 lifecycle methods for the currently open Activity (such as {@link
392 android.app.Activity#onPause()}) are called. Your Activity just loses input focus as it is given to
393 the search dialog.
394 </p>
395
396 <p>If you want to be notified when search is invoked, override the {@link
397 android.app.Activity#onSearchRequested()} method. When the system calls this method, you can do any
398 work you want to when your Activity looses input focus to the search dialog (such as pause
399 animations). Unless you are <a href="#SearchContextData">passing search context data</a>
400 (discussed below), you should end the method by calling the super class implementation. For
401 example:</p>
402
403 <pre>
404 &#64;Override
405 public boolean onSearchRequested() {
406     pauseSomeStuff();
407     return super.onSearchRequested();
408 }
409 </pre>
410
411 <p>If the user cancels search by pressing the BACK key, the Activity in which search was
412 invoked re-gains input focus. You can register to be notified when the search dialog is
413 closed with {@link android.app.SearchManager#setOnDismissListener(SearchManager.OnDismissListener)
414 setOnDismissListener()}
415 and/or {@link android.app.SearchManager#setOnCancelListener(SearchManager.OnCancelListener)
416 setOnCancelListener()}. You
417 should need to register only the {@link android.app.SearchManager.OnDismissListener
418 OnDismissListener}, because it is called every time the search dialog closes. The {@link
419 android.app.SearchManager.OnCancelListener OnCancelListener} only pertains to events in which the
420 user explicitly exited the search dialog, so it is not called when a search is executed (in which
421 case, the search dialog naturally disappears).</p>
422
423 <p>If the current Activity is not the searchable Activity, then the normal Activity lifecycle
424 events are triggered once the user executes a search (the current Activity receives {@link
425 android.app.Activity#onPause()} and so forth, as
426 described in <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">Application
427 Fundamentals</a>). If, however, the current Activity is the searchable Activity, then one of two
428 things happens:</p>
429
430 <ol type="a">
431   <li>By default, the searchable Activity receives the {@link
432 android.content.Intent#ACTION_SEARCH} Intent with a call to {@link
433 android.app.Activity#onCreate(Bundle) onCreate()} and a new instance of the
434 Activity is brought to the top of the Activity stack. There are now two instances of your
435 searchable Activity in the Activity stack (so pressing the BACK key goes back to the previous
436 instance of the searchable Activity, rather than exiting the searchable Activity).</li>
437   <li>If you set {@code android:launchMode} to "singleTop", then the
438 searchable Activity receives the {@link android.content.Intent#ACTION_SEARCH} Intent with a call
439 to {@link android.app.Activity#onNewIntent(Intent)}, passing the new {@link
440 android.content.Intent#ACTION_SEARCH} Intent here. For example, here's how you might handle
441 this case, in which the searchable Activity's launch mode is "singleTop":
442 <pre>
443 &#64;Override
444 public void onCreate(Bundle savedInstanceState) {
445     super.onCreate(savedInstanceState);
446     setContentView(R.layout.search);
447     handleIntent(getIntent());
448 }
449
450 &#64;Override
451 protected void onNewIntent(Intent intent) {
452     setIntent(intent);
453     handleIntent(intent);
454 }
455
456 private void handleIntent(Intent intent) {
457     if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
458       String query = intent.getStringExtra(SearchManager.QUERY);
459       doMySearch(query);
460     }
461 }
462 </pre>
463
464 <p>Compared to the example code in the section about <a href="#PerformingSearch">Performing a
465 Search</a>, all the code to handle the
466 search Intent is now in the {@code handleIntent()} method, so that both {@link
467 android.app.Activity#onCreate(Bundle)
468 onCreate()} and {@link android.app.Activity#onNewIntent(Intent) onNewIntent()} can execute it.</p>
469
470 <p>When the system calls {@link android.app.Activity#onNewIntent(Intent)}, the Activity has
471 not been restarted, so the {@link android.app.Activity#getIntent()} method
472 returns the same Intent that was received with {@link
473 android.app.Activity#onCreate(Bundle) onCreate()}. This is why you should call {@link
474 android.app.Activity#setIntent(Intent)} inside {@link
475 android.app.Activity#onNewIntent(Intent)} (so that the Intent saved by the Activity is updated in
476 case you call {@link android.app.Activity#getIntent()} in the future).</p>
477
478 </li>
479 </ol>
480
481 <p>The second scenario using "singleTop" launch mode is usually ideal, because chances are good that
482 once a search is done, the user will perform additional searches and it's a bad experience if your
483 application creates multiple instances of the searchable Activity. So, we recommend that you set
484 your searchable Activity to "singleTop" launch mode in the application
485 manifest. For example:</p>
486
487 <pre>
488 &lt;activity android:name=".MySearchableActivity"
489           <b>android:launchMode="singleTop"</b> >
490     &lt;intent-filter>
491         &lt;action android:name="android.intent.action.SEARCH" />
492     &lt;/intent-filter>
493     &lt;meta-data android:name="android.app.searchable"
494                       android:resource="@xml/searchable"/>
495   &lt;/activity>
496 </pre>
497
498
499
500 <h2 id="SearchContextData">Passing Search Context Data</h2>
501
502 <p>To refine your search criteria from the current Activity instead of depending only on the user's
503 search query, you can provide additional data in the Intent that the Search Manager sends to your
504 searchable Activity. In a simple case, you can make your refinements inside the searchable
505 Activity, for every search made, but if your
506 search criteria varies from one searchable context to another, then you can pass whatever data
507 is necessary to refine your search in the {@link android.app.SearchManager#APP_DATA} {@link
508 android.os.Bundle}, which is included in the {@link android.content.Intent#ACTION_SEARCH}
509 Intent.</p>
510
511 <p>To pass this kind of data to your searchable Activity, override  {@link
512 android.app.Activity#onSearchRequested()} method for the Activity in which search can be invoked.
513 For example:</p>
514
515 <pre>
516 &#64;Override
517 public boolean onSearchRequested() {
518      Bundle appData = new Bundle();
519      appData.putBoolean(MySearchableActivity.JARGON, true);
520      startSearch(null, false, appData, false);
521      return true;
522  }
523 </pre>
524
525 <p>Returning "true" indicates that you have successfully handled this callback event. Then in your
526 searchable Activity, you can extract the data placed inside {@code appdata} from the {@link
527 android.app.SearchManager#APP_DATA} {@link android.os.Bundle} to refine the search. For example:</p>
528
529 <pre>
530 Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);
531 if (appData != null) {
532     boolean jargon = appData.getBoolean(MySearchableActivity.JARGON);
533 }
534 </pre>
535
536 <p class="caution"><strong>Caution:</strong> Never call the {@link
537 android.app.Activity#startSearch(String,boolean,Bundle,boolean) startSearch()} method from outside
538 the {@link android.app.Activity#onSearchRequested()} callback method. To invoke the search dialog
539 in your Activity, always call {@link android.app.Activity#onSearchRequested()}. Otherwise, {@link
540 android.app.Activity#onSearchRequested()} is not called and customizations (such as the addition of
541 {@code appData} in the above example) are missed.</p>
542
543
544 <h2 id="VoiceSearch">Adding Voice Search</h2>
545
546 <p>You can add voice search functionality to your search dialog by adding the {@code
547 android:voiceSearchMode} attribute to your searchable configuration. This adds a voice search
548 button in the search dialog that launches a voice prompt. When the user
549 has finished speaking, the transcribed search query is sent to your searchable
550 Activity.</p>
551
552 <p>For example:</p>
553
554 <pre>
555 &lt;?xml version="1.0" encoding="utf-8"?>
556 &lt;searchable xmlns:android="http://schemas.android.com/apk/res/android"
557     android:label="@string/search_label"
558     android:hint="@string/search_hint"
559     <b>android:voiceSearchMode="showVoiceSearchButton|launchRecognizer"</b> >
560 &lt;/searchable>
561 </pre>
562
563 <p>The value {@code showVoiceSearchButton} is required to enable voice
564 search, while the second value, {@code launchRecognizer}, specifies that the voice search button
565 should launch a recognizer that returns the transcribed text to the searchable Activity.</p>
566
567 <p>You can provide additional attributes to specify the voice search behavior, such
568 as the language to be expected and the maximum number of results to return. See the <a
569 href="searchable-config.html">Searchable Configuration</a> reference for more information about the
570 available attributes.</p>
571
572 <p class="note"><strong>Note:</strong> Carefully consider whether voice search is appropriate for
573 your application. All searches performed with the voice search button are immediately sent to
574 your searchable Activity without a chance for the user to review the transcribed query. Sufficiently
575 test the voice recognition and ensure that it understands the types of queries that
576 the user might submit inside your application.</p>