diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index 13d752a369223..dce78c4b3ecbc 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -143,6 +143,7 @@
  • <intent-filter>
  • <manifest>
  • <meta-data>
  • +
  • <path-permission>
  • <permission>
  • <permission-group>
  • <permission-tree>
  • @@ -198,7 +199,18 @@
  • Bluetooth - new!
  • + +
  • +
    + Search + new!
    + +
  • diff --git a/docs/html/guide/topics/search/adding-custom-suggestions.jd b/docs/html/guide/topics/search/adding-custom-suggestions.jd new file mode 100644 index 0000000000000..9ea4c8be48ea2 --- /dev/null +++ b/docs/html/guide/topics/search/adding-custom-suggestions.jd @@ -0,0 +1,699 @@ +page.title=Adding Custom Suggestions +parent.title=Search +parent.link=index.html +@jd:body + +
    +
    +

    Key classes

    +
      +
    1. {@link android.app.SearchManager}
    2. +
    3. {@link android.content.SearchRecentSuggestionsProvider}
    4. +
    5. {@link android.content.ContentProvider}
    6. +
    +

    In this document

    +
      +
    1. The Basics
    2. +
    3. Modifying the searchable configuration
    4. +
    5. Creating a Content Provider +
        +
      1. Handling a suggestion query
      2. +
      3. Building a suggestion table
      4. +
      +
    6. +
    7. Declaring an Intent for suggestions +
        +
      1. Declaring the Intent action
      2. +
      3. Declaring the Intent data
      4. +
      +
    8. +
    9. Handling the Intent
    10. +
    11. Rewriting the query text
    12. +
    13. Exposing search suggestions to Quick Search Box
    14. +
    +

    See also

    +
      +
    1. Searchable Configuration
    2. +
    3. Content Providers
    4. +
    5. Searchable +Dictionary sample app
    6. +
    +
    +
    + +

    The Android search framework provides the ability for your application to +provide suggestions while the user types into the Android search dialog. In this guide, you'll learn +how to create custom suggestions. These are suggestions based on custom data provided by your +application. For example, if your application is a word dictionary, you can suggest words from the +dictionary that match the text entered so far. These are the most valuable suggestions because you +can effectively predict what the user wants and provide instant access to it. Once you provide +custom suggestions, you then make them available to the system-wide Quick Search Box, providing +access to your content from outside your application.

    + +

    Before you begin, you need to have implemented the Android search dialog for searches in your +application. If you haven't done this, see Using the Android Search +Dialog.

    + + +

    The Basics

    + + + +

    When the user selects a custom suggestions, the Search Manager will send a customized Intent to +your searchable Activity. Whereas a normal search query will send an Intent with the {@link +android.content.Intent#ACTION_SEARCH} action, you can instead define your custom suggestions to use +{@link android.content.Intent#ACTION_VIEW} (or any other action), and also include additional data +that's relevant to the selected suggestion. Continuing +the dictionary example, when the user selects a suggestion, your application can immediately +open the definition for that word, instead of searching the dictionary for matches.

    + +

    To provide custom suggestions, you need to do the following:

    + + + +

    Just like the Search Manager handles the rendering of the search dialog, it will also do the work +to display all search suggestions below the search dialog. All you need to do is provide a source +from which the suggestions can be retrieved.

    + +

    Note: If you're not familiar with creating Content +Providers, please read the Content +Providers developer guide before you continue.

    + +

    When the Search Manager identifies that your Activity is searchable and also provides search +suggestions, the following procedure will take place as soon as the user types into the Android +search box:

    + + + +

    At this point, the following may happen:

    + + + + + +

    Modifying the searchable configuration

    + +

    To add support for custom suggestions, add the {@code android:searchSuggestAuthority} attribute +to the {@code <searchable>} element in your searchable configuration file. For example:

    + +
    +<?xml version="1.0" encoding="utf-8"?>
    +<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    +    android:label="@string/app_label"
    +    android:hint="@string/search_hint"
    +    android:searchSuggestAuthority="my.package.MyCustomSuggestionProvider" >
    +</searchable>
    +
    + +

    You may require some additional attributes, depending on the type of Intent you attach +to each suggestion and how you want to format queries to your content provider. The other optional +attributes are discussed in the relevant sections below.

    + + +

    Creating a Content Provider

    + +

    Creating a content provider for custom suggestions requires previous knowledge about Content +Providers that's covered in the Content Provider developer +guide. For the most part, a content provider for custom suggestions is the +same as any other content provider. However, for each suggestion you provide, the respective row in +the {@link android.database.Cursor} must include specific columns that the Search Manager +understands.

    + +

    When the user starts typing into the search dialog, the Search Manager will query your Content +Provider for suggestions by calling {@link +android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} each time +a letter is typed. In your implementation of {@link +android.content.ContentProvider#query(Uri,String[],String,String[],String) query()}, your +content provider must search your suggestion data and return a {@link +android.database.Cursor} that points to the rows you determine to be good suggestions.

    + +

    The following two sections describe how the Search Manager will send requests to your Content +Provider and how you can handle them, and define the columns that the Search Manager understands and +expects to be provided in the {@link android.database.Cursor} returned with each query.

    + + +

    Handling the suggestion query

    + +

    When the Search Manager makes a request for suggestions from your content provider, it will call +{@link android.content.ContentProvider#query(Uri,String[],String,String[],String)}. You must +implement this method in your content provider so that it will search your suggestions and return a +Cursor that contains the suggestions you deem relevant.

    + +

    Here's a summary of the parameters that the Search Manager will pass to your {@link +android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method +(listed in order):

    + +
    +
    uri
    +
    This will always be a content {@link android.net.Uri}, formatted as: +
    +content://your.authority/optional.suggest.path/{@link
    +android.app.SearchManager#SUGGEST_URI_PATH_QUERY}
    +
    +

    The default behavior is for Search Manager to pass this URI and append it with the query text. +For example:

    +
    +content://your.authority/optional.suggest.path/{@link
    +android.app.SearchManager#SUGGEST_URI_PATH_QUERY}/puppies
    +
    +

    The query text on the end will be encoded using URI encoding rules, so you may need to decode +it.

    +

    The {@code optional.suggest.path} portion is only included in the URI if you have set +such a path in your searchable configuration file with the {@code android:searchSuggestPath} +attribute. This is only needed if you use the same content provider for multiple searchable +activities, in which case you need to disambiguate the source of the suggestion query.

    +

    Note that {@link android.app.SearchManager#SUGGEST_URI_PATH_QUERY} is not the literal +string provided in the URI, but a constant that you should use if you need to refer to this +path.

    +
    + +
    projection
    +
    This is always null
    + +
    selection
    +
    This is the value provided in the {@code android:searchSuggestSelection} attribute of +your searchable configuration file, or null if you have not declared the {@code +android:searchSuggestSelection} attribute. More about this below.
    + +
    selectionArgs
    +
    This contains the search query as the first (and only) element of the array if you have +declared the {@code android:searchSuggestSelection} attribute in your searchable configuration. If +you have not declared {@code android:searchSuggestSelection}, then this parameter is null. More +about this below.
    + +
    sortOrder
    +
    This is always null
    +
    + +

    As you may have realized, there are two ways by which the Search Manager can send you the search +query text. The default manner is for the query text to be included as the last path of the content +URI that is passed in the {@code uri} parameter. However, if you include a selection value in your +searchable configuration's {@code +android:searchSuggestSelection} attribute, then the query text will instead be passed as the first +element of the {@code selectionArgs} string array. Both options are summarized below.

    + + +

    Get the query in the Uri

    + +

    By default, the query will be appended as the last segment of the {@code uri} +parameter (a {@link android.net.Uri} object). To retrieve the query text in this case, simply use +{@link android.net.Uri#getLastPathSegment()}. For example:

    + +
    +String query = uri.getLastPathSegment().toLowerCase();
    +
    + +

    This will return the last segment of the Uri, which is the query text entered in the search +dialog.

    + + + +

    Get the query in the selection arguments

    + +

    Instead of using the URI, you may decide it makes more sense for your {@link +android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method to +receive everything it needs to perform the look-up and you want the +{@code selection} and {@code selectionArgs} parameters to carry values. In this case, you can +add the {@code android:searchSuggestSelection} attribute to your searchable configuration with your +SQLite selection string. In this selection string, you can include a question mark ("?") as +a placeholder for the actual search query. This selection string will be delivered as the +{@code selection} string parameter, and the query entered into the search dialog will be delivered +as the first element in the {@code selectionArgs} string array parameter.

    + +

    For example, here's how you might form the {@code android:searchSuggestSelection} attribute to +create a full-text search statement:

    + +
    +<?xml version="1.0" encoding="utf-8"?>
    +<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    +    android:label="@string/app_label"
    +    android:hint="@string/search_hint"
    +    android:searchSuggestAuthority="my.package.MyCustomSuggestionProvider"
    +    android:searchSuggestIntentAction="android.Intent.action.VIEW"
    +    android:searchSuggestSelection="word MATCH ?">
    +</searchable>
    +
    + +

    When you then receive the {@code selection} and {@code selectionArgs} parameters in your {@link +android.content.ContentProvider#query(Uri,String[],String,String[],String) ContentProvider.query()} +method, they will carry the selection ("word MATCH ?") and the query text, respectively. When +these are passed to an SQLite {@link +android.database.sqlite.SQLiteDatabase#query(String,String[],String,String[],String,String, +String) query} method, they will be synthesized together (replacing the question mark with the query +text, wrapped in single-quotes). Note that if you chose this method and need to add any wildcards to +your query text, you must do so by appending (and/or prefixing) them to the {@code selectionArgs} +parameter, because this is the value that will be wrapped in quotes and inserted in place of the +question mark.

    + +

    Tip: If you don't want to define a selection clause in +the {@code android:searchSuggestSelection} attribute, but would still like to receive the query +text in the {@code selectionArgs} parameter, simply provide a non-null value for the {@code +android:searchSuggestSelection} attribute. This will trigger the query to be passed in {@code +selectionArgs} and you can ignore the {@code selection} parameter. In this way, you can instead +define the actual selection clause at a lower level so that your content provider doesn't have to +handle it.

    + + + +

    Building a suggestion table

    + + + +

    When you return suggestions to the Search Manager with a {@link android.database.Cursor}, the +Search Manager expects there to be specific columns in each row. So, regardless of whether you +decide to store +your suggestion data in an SQLite database on the device, a database on a web server, or another +format on the device or web, you must format the suggestions as rows in a table and +present them with a {@link android.database.Cursor}. There are several columns that the Search +Manager will understand, but only two are required:

    + +
    +
    {@link android.provider.BaseColumns#_ID}
    +
    This is the unique row ID for each suggestion. The search dialog requires this in order +to present the suggestions in a ListView.
    +
    {@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}
    +
    This is the line of text that will be presented to the user as a suggestion.
    +
    + +

    The following columns are all optional (and most will be discussed further in the following +sections, so you may want to skip this list for now):

    + +
    +
    {@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_2}
    +
    If your Cursor includes this column, then all suggestions will be provided in a two-line +format. The data in this column will be displayed as a second, smaller line of text below the +primary suggestion text. It can be null or empty to indicate no secondary text.
    +
    {@link android.app.SearchManager#SUGGEST_COLUMN_ICON_1}
    +
    If your Cursor includes this column, then all suggestions will be provided in an +icon-plus-text format with the icon on the left side. This value should be a reference to the +icon. It can be null or zero to indicate no icon in this row.
    +
    {@link android.app.SearchManager#SUGGEST_COLUMN_ICON_2}
    +
    If your Cursor includes this column, then all suggestions will be provided in an +icon-plus-text format with the icon on the right side. This value should be a reference to the +icon. It can be null or zero to indicate no icon in this row.
    +
    {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION}
    +
    If this column exists and this element exists at the given row, this is the action that will +be used when forming the suggestion's Intent . If the element is not provided, the action will be +taken from the {@code android:searchSuggestIntentAction} field in your searchable configuration. At +least one of these +must be present for the suggestion to generate an Intent. Note: If your action is the same for all +suggestions, it is more efficient to specify the action using {@code +android:searchSuggestIntentAction} and omit this column from the Cursor .
    +
    {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA}
    +
    If this column exists and this element exists at the given row, this is the data that will be +used when forming the suggestion's Intent. If the element is not provided, the data will be taken +from the {@code android:searchSuggestIntentData} field in your searchable configuration. If neither +source is provided, +the Intent's data field will be null. Note: If your data is the same for all suggestions, or can be +described using a constant part and a specific ID, it is more efficient to specify it using {@code +android:searchSuggestIntentData} and omit this column from the Cursor . +
    +
    {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID}
    +
    If this column exists and this element exists at the given row, then "/" and this value will +be appended to the data field in the Intent. This should only be used if the data field specified +by the {@code android:searchSuggestIntentData} attribute in the searchable configuration has already +been set to an appropriate base string.
    +
    {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_EXTRA_DATA}
    +
    If this column exists and this element exists at a given row, this is the extra data +that will be used when forming the suggestion's Intent. If not provided, the Intent's extra data +field will be +null. This column allows suggestions to provide additional arbitrary data which will be +included as an extra in the Intent's {@link android.app.SearchManager#EXTRA_DATA_KEY} key.
    +
    {@link android.app.SearchManager#SUGGEST_COLUMN_QUERY}
    +
    If this column exists and this element exists at the given row, this is the data that will be +used when forming the suggestion's query, included as an extra in the Intent's {@link +android.app.SearchManager#QUERY} key. Required if suggestion's action is {@link +android.content.Intent#ACTION_SEARCH}, optional otherwise.
    +
    {@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID}
    +
    Only used when providing suggestions for Quick Search Box. This column is used to indicate +whether a search suggestion should be stored as a +shortcut, and whether it should be validated. Shortcuts are usually formed when the user clicks a +suggestion from Quick Search Box. If missing, the result will be stored as a shortcut and never +refreshed. If set to {@link android.app.SearchManager#SUGGEST_NEVER_MAKE_SHORTCUT}, the result will +not be stored as a shortcut. +Otherwise, the shortcut id will be used to check back for for an up to date suggestion using +{@link android.app.SearchManager#SUGGEST_URI_PATH_SHORTCUT}.
    +
    {@link android.app.SearchManager#SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING}
    +
    Only used when providing suggestions for Quick Search Box. This column is used to specify that +a spinner should be shown instead of an icon from {@link +android.app.SearchManager#SUGGEST_COLUMN_ICON_2} +while the shortcut of this suggestion is being refreshed in Quick Search Box.
    +
    + +

    Again, most of these columns will be discussed in the relevant sections below, so don't worry if +they don't make sense to you now.

    + + + +

    Declaring an Intent for suggestions

    + +

    When the user selects a suggestion from the list that appears below the search +dialog (instead of performing a search), the Search Manager will send +a custom {@link android.content.Intent} to your searchable Activity. You must define both the +action and data for the Intent.

    + + +

    Declaring the Intent action

    + +

    The most common Intent action for a custom suggestion is {@link +android.content.Intent#ACTION_VIEW}, which is appropriate when +you want to open something, like the definition for a word, a person's contact information, or a web +page. However, the Intent action can be whatever you want and can even be different for each +suggestion.

    + +

    To declare an Intent action that will be the same for all suggestions, define the action in +the {@code android:searchSuggestIntentAction} attribute of your searchable configuration file. For +example:

    + +
    +<?xml version="1.0" encoding="utf-8"?>
    +<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    +    android:label="@string/app_label"
    +    android:hint="@string/search_hint"
    +    android:searchSuggestAuthority="my.package.MySuggestionProvider"
    +    android:searchSuggestIntentAction="android.Intent.action.VIEW" >
    +</searchable>
    +
    + +

    If you want to declare an Intent action that's unique for each suggestion, add the {@link +android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column to +your suggestions table and, for each suggestion, place in it the action to use (such as +{@code "android.Intent.action.VIEW"}).

    + +

    You can also combine these two techniques. For instance, you can include the {@code +android:searchSuggestIntentAction} attribute with an action to be used with all suggestions by +default, then override this action for some suggestions by declaring a different action in the +{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column. If you do not include +a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column, then the +Intent provided in the {@code android:searchSuggestIntentAction} attribute will be used.

    + +

    Note: If you do not include the +{@code android:searchSuggestIntentAction} attribute in your searchable configuration, then you +must include a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} +column for every suggestion, or the Intent will fail.

    + + +

    Declaring Intent data

    + +

    When the user selects a suggestion, your searchable Activity will receive the Intent with the +action you've defined (as discussed in the previous section), but the Intent must also carry +data in order for your Activity to identify which suggestions was selected. Specifically, +the data should be something unique for each suggestion, such as the row ID for the suggestion in +your suggestions table. When the Intent is received, +you can retrieve the attached data with {@link android.content.Intent#getData()} or {@link +android.content.Intent#getDataString()}.

    + +

    There are two ways to define the data that is included with the Intent:

    + +
      +
    1. Define the data for each suggestion inside the {@link +android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column of your suggestions table.
    2. +
    3. Fragment a data URI into two pieces: the portion common to all suggestions and the portion +unique to each suggestion. Place these parts into the {@code android:searchSuggestIntentData} +attribute of the searchable configuration and the {@link +android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column of your +suggestions table, respectively.
    4. +
    + +

    The first option is straight-forward. Simply provide all necessary data information for each +Intent in the suggestions table by including the {@link +android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column and then populating it with unique +data for each row. The data from this column will be attached to the Intent exactly as it +is found in this column. You can then retrieve it with with {@link android.content.Intent#getData()} +or {@link android.content.Intent#getDataString()}.

    + +

    Tip: It's usually easiest to use the table's row ID as the +Intent data because it's always unique. And the easiest way to do that is by using the +{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column name as an alias for the row ID +column. See the Searchable Dictionary sample +app for an example in which {@link android.database.sqlite.SQLiteQueryBuilder} is used to +create a projection map of column names to aliases.

    + +

    The second option is to fragment your data URI into the common piece and the unique piece. +Declare the piece of the URI that is common to all suggestions in the {@code +android:searchSuggestIntentData} attribute of your searchable configuration. For example:

    + +
    +<?xml version="1.0" encoding="utf-8"?>
    +<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    +    android:label="@string/app_label"
    +    android:hint="@string/search_hint"
    +    android:searchSuggestAuthority="my.package.MySuggestionProvider"
    +    android:searchSuggestIntentAction="android.Intent.action.VIEW"
    +    android:searchSuggestIntentData="content://my.package/datatable" >
    +</searchable>
    +
    + +

    Now include the final path for each suggestion (the unique part) in the {@link +android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} +column of your suggestions table. When the user selects a suggestion, the Search Manager will take +the string from {@code android:searchSuggestIntentData}, append a slash ("/") and then add the +respective value from the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column to +form a complete content URI. You can then retrieve the {@link android.net.Uri} with with {@link +android.content.Intent#getData()}.

    + +

    Add more data

    + +

    If you need to express even more information with your Intent, you can add another table column, +{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_EXTRA_DATA}, which can store additional +information about the suggestion. The data saved in this column will be placed in {@link +android.app.SearchManager#EXTRA_DATA_KEY} of the Intent's extra Bundle.

    + + +

    Handling the Intent

    + +

    Now that your search dialog provides custom search suggestions with custom formatted Intents, you +need your searchable Activity to handle these Intents as they are delivered once the user selects a +suggestion. (This is, of course, in addition to handling the {@link +android.content.Intent#ACTION_SEARCH} Intent, which your searchable Activity already does.) +Accepting the new Intent is rather self-explanatory, so we'll skip straight to an example:

    + +
    +Intent intent = getIntent();
    +if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
    +    // Handle the normal search query case
    +    String query = intent.getStringExtra(SearchManager.QUERY);
    +    doSearch(query);
    +} else if (Intent.ACTION_VIEW.equals(intent.getAction())) {
    +    // Handle a suggestions click (because my suggestions all use ACTION_VIEW)
    +    Uri data = intent.getData());
    +    showResult(rowId);
    +}
    +
    + +

    In this example, the Intent action is {@link +android.content.Intent#ACTION_VIEW} and the data carries a complete URI pointing to the suggested +item, as synthesized by the {@code android:searchSuggestIntentData} string and {@link +android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column. The URI is then passed to a local +method that will query the content provider for the item specified by the URI and show it.

    + + + +

    Rewriting the query text

    + +

    If the user navigates through the suggestions list using the device directional controls, the +text in the search dialog won't change, by default. However, you can temporarily rewrite the +user's query text as it appears in the text box with +a query that matches the currently selected suggestion. This enables the user to see what query is +being suggested (if appropriate) and then select the search box and edit the query before +dispatching it as a search.

    + +

    You can rewrite the query text in the following ways:

    + +
      +
    1. Add the {@code android:searchMode} attribute to your searchable configuration with the +"queryRewriteFromText" value. In this case, the content from the suggestion's {@link +android.app.SearchManager#SUGGEST_COLUMN_TEXT_1} +column will be used to rewrite the query text.
    2. +
    3. Add the {@code android:searchMode} attribute to your searchable configuration with the +"queryRewriteFromData" value. In this case, the content from the suggestion's +{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column will be used to rewrite the +query text. Note that this should only +be used with Uri's or other data formats that are intended to be user-visible, such as HTTP URLs. +Internal Uri schemes should not be used to rewrite the query in this way.
    4. +
    5. Provide a unique query text string in the {@link +android.app.SearchManager#SUGGEST_COLUMN_QUERY} column of your suggestions table. If this column is +present and contains a value for the current suggestion, it will be used to rewrite the query text +(and override either of the previous implementations).
    6. +
    + + +

    Exposing search suggestions to Quick Search Box

    + +

    Once your application is configured to provide custom search suggestions, making them available +to the globally-accessible Quick Search Box is as easy as modifying your searchable configuration to +include {@code android:includeInGlobalSearch} as "true".

    + +

    The only scenario in which additional work will be required is if your content provider for +custom suggestions requires a permission for read access. In which case, you need to add a special +{@code <path-permission>} element for the provider to grant Quick Search Box read access to your +content provider. For example:

    + +
    +<provider android:name="MySuggestionProvider"
    +          android:authorities="my.package.authority"
    +          android:readPermission="com.example.provider.READ_MY_DATA"
    +          android:writePermission="com.example.provider.WRITE_MY_DATA">
    +  <path-permission android:pathPrefix="/search_suggest_query"
    +                   android:readPermission="android.permission.GLOBAL_SEARCH" />
    +</provider>
    +
    + +

    In this example, the provider restricts read and write access to the content. The +{@code <path-permission>} element amends the restriction by granting read access to content +inside the {@code "/search_suggest_query"} path prefix when the {@code +"android.permission.GLOBAL_SEARCH"} permission exists. This grants access to Quick Search Box +so that it may query your content provider for suggestions.

    + +

    Content providers that enforce no permissions are already available to the search +infrastructure.

    + + +

    Enabling suggestions on a device

    + +

    When your application is configured to provide suggestions in Quick Search Box, it is not +actually enabled to provide suggestions in Quick Search Box, by default. It is the user's choice +whether to include suggestions from your application in the Quick Search Box. To enable search +suggestions from your application, the user must open "Searchable items" (in Settings > Search) and +enable your application as a searchable item.

    + +

    Each application that is available to Quick Search Box has an entry in the Searchable items +settings page. The entry includes the name of the application and a short description of what +content can be searched from the application and made available for suggestions in Quick Search Box. +To define the description text for your searchable application, add the {@code +android:searchSettingsDescription} attribute to your searchable configuration. For example:

    + +
    +<?xml version="1.0" encoding="utf-8"?>
    +<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    +    android:label="@string/app_label"
    +    android:hint="@string/search_hint"
    +    android:searchSuggestAuthority="my.package.MySuggestionProvider"
    +    android:searchSuggestIntentAction="android.Intent.action.VIEW"
    +    android:includeInGlobalSearch="true"
    +    android:searchSettingsDescription="@string/search_description" >
    +</searchable>
    +
    + +

    The string for {@code android:searchSettingsDescription} should be as concise as possible and +state the content that is searchable. For example, "Artists, albums, and tracks" for a music +application, or "Saved notes" for a notepad application. Providing this description is important so +the user knows what kind of suggestions will be provided. This attribute should always be included +when {@code android:includeInGlobalSearch} is "true".

    + +

    Remember that the user must visit this settings menu to enable search suggestions for your +application before your search suggestions will appear in Quick Search Box. As such, if search is an +important aspect of your application, then you may want to consider a way to message this to your +users — perhaps with a note the first time they launch the app about how to enable search +suggestions for Quick Search Box.

    + + +

    Managing Quick Search Box suggestion shortcuts

    + +

    Suggestions that the user selects from Quick Search Box may be automatically made into shortcuts. +These are suggestions that the Search Manager has copied from your content provider so it can +quickly access the suggestion without the need to re-query your content provider.

    + +

    By default, this is enabled for all suggestions retrieved by Quick Search Box, but if your +suggestion data may change over time, then you can request that the shortcuts be refreshed. For +instance, if your suggestions refer to dynamic data, such as a contact's presence status, then you +should request that the suggestion shortcuts be refreshed when shown to the user. To do so, +include the {@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} in your suggestions table. +Using this column, you can +configure the shortcut behavior for each suggestion in the following ways:

    + +
      +
    1. Have Quick Search Box re-query your content provider for a fresh version of the shortcutted +suggestion. +

      Provide a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} column +and the suggestion will be +re-queried for a fresh version of the suggestion each time the shortcut is displayed. The shortcut +will be quickly displayed with whatever data was most recently available until the refresh query +returns, after which the suggestion will be dynamically refreshed with the new information. The +refresh query will be sent to your content provider with a URI path of {@link +android.app.SearchManager#SUGGEST_URI_PATH_SHORTCUT} +(instead of {@link android.app.SearchManager#SUGGEST_URI_PATH_QUERY}). The Cursor you return should +contain one suggestion using the +same columns as the original suggestion, or be empty, indicating that the shortcut is no +longer valid (in which case, the suggestion will disappear and the shortcut will be removed).

      +

      If a suggestion refers to data that could take longer to refresh, such as a network based +refresh, you may also add the {@link +android.app.SearchManager#SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING} column to your suggestions +table with a value +of "true" in order to show a progress spinner for the right hand icon until the refresh is complete. +(Any value other than "true" will not show the progress spinner.)

    2. +
    3. Prevent the suggestion from being copied into a shortcut at all. +

      Provide a value of {@link android.app.SearchManager#SUGGEST_NEVER_MAKE_SHORTCUT} in the +{@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} column. In +this case, the suggestion will never be copied into a shortcut. This should only be necessary if you +absolutely do not want the previously copied suggestion to appear at all. (Recall that if you +provide a normal value for the column then the suggestion shortcut will appear only until the +refresh query returns.)

    4. +
    5. Allow the default shortcut behavior to apply. +

      Simply leave the {@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} empty for each +suggestion that will not change and can be saved as a shortcut.

    6. +
    + +

    Of course, if none of your suggestions will ever change, then you do not need the +{@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} column at all.

    + +

    Note: Quick Search Box will ultimately decide whether to shortcut +your app's suggestions, considering these values as a strong request from your application.

    + + +

    About Quick Search Box suggestion ranking

    + +

    Once your application's search results are made available to Quick Search Box, how they surface +to the user for a particular query will be determined as appropriate by Quick Search Box ranking. +This may depend on how many other apps have results for that query, and how often the user has +selected on your results compared to those of the other apps. There is no guarantee about how +ranking will occur, or whether your app's suggestions will show at all for a given query. In +general, you can expect that providing quality results will increase the likelihood that your app's +suggestions are provided in a prominent position, and apps that provide lower quality suggestions +will be more likely to be ranked lower and/or not displayed.

    + +
    +

    See the Searchable +Dictionary sample app for a complete demonstration of custom search suggestions.

    +
    + diff --git a/docs/html/guide/topics/search/adding-recent-query-suggestions.jd b/docs/html/guide/topics/search/adding-recent-query-suggestions.jd new file mode 100644 index 0000000000000..37e0e8275edff --- /dev/null +++ b/docs/html/guide/topics/search/adding-recent-query-suggestions.jd @@ -0,0 +1,225 @@ +page.title=Adding Recent Query Suggestions +parent.title=Search +parent.link=index.html +@jd:body + +
    +
    +

    Key classes

    +
      +
    1. {@link android.provider.SearchRecentSuggestions}
    2. +
    3. {@link android.content.SearchRecentSuggestionsProvider}
    4. +
    +

    In this document

    +
      +
    1. The Basics
    2. +
    3. Modifying the searchable +configuration
    4. +
    5. Creating a Content Provider
    6. +
    7. Saving queries
    8. +
    9. Clearing the suggestion data
    10. +
    +

    See also

    +
      +
    1. Searchable Configuration
    2. +
    +
    +
    + +

    The Android search framework provides the ability for your application to +provide suggestions while the user types into the Android search dialog. In this guide, you'll learn +how to create recent query suggestions. These are suggestions based +on queries previously entered by the user. So, if the user previously searched for "puppies" then it +will appear as a suggestion as they begin typing the same string of text. The screenshot below +shows an example of recent query suggestions.

    + +

    Before you begin, you need to have implemented the Android search dialog for searches in your +application. If you haven't done this, see Using the Android Search +Dialog.

    + + +

    The Basics

    + + + +

    Recent query suggestions are simply saved searches. When the user selects one of +the suggestions, your searchable Activity will receive a normal {@link +android.content.Intent#ACTION_SEARCH} Intent with the suggestion as the search query, which your +searchable Activity will already handle.

    + +

    To provide recent queries suggestions, you need to:

    + + + +

    Just like the Search Manager handles the rendering of the search dialog, it will also do the work +to display all search suggestions below the search dialog. All you need to do is provide a source +from which the suggestions can be retrieved.

    + +

    When the Search Manager identifies that your Activity is searchable and also provides search +suggestions, the following procedure will take place as soon as the user types into the Android +search box:

    + + + +

    At this point, the following may happen:

    + + + +

    As you'll soon discover, the {@link android.content.SearchRecentSuggestionsProvider} class that +you'll extend for your content provider will automatically do the work described above, so there's +actually very little code to write.

    + + +

    Modifying the searchable configuration

    + +

    First, you need to add the {@code android:searchSuggestAuthority} and +{@code android:searchSuggestSelection} attributes to the {@code <searchable>} element in your +searchable configuration file. For example:

    + +
    +<?xml version="1.0" encoding="utf-8"?>
    +<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    +    android:label="@string/app_label"
    +    android:hint="@string/search_hint"
    +    android:searchSuggestAuthority="my.package.MySuggestionProvider"
    +    android:searchSuggestSelection=" ?" >
    +</searchable>
    +
    + +

    The value for {@code android:searchSuggestAuthority} should be a fully-qualified name for +your content provider: your application package name followed by the name of your content provider. +This string must match the authority used in the content provider (discussed in the next section). +

    + +

    The value for {@code android:searchSuggestSelection} must be a single question-mark, preceded by +a space (" ?"), which is simply a placeholder for the SQLite selection argument (which will be +automatically replaced by the query text entered by the user).

    + + +

    Creating a Content Provider

    + +

    The content provider that you need for recent query suggestions must be an implementation +of {@link android.content.SearchRecentSuggestionsProvider}. This class does practically everything +for you. All you have to do is write a class constructor that executes one line of code.

    + +

    For example, here's a complete implementation of a content provider for recent query +suggestions:

    + +
    +public class MySuggestionProvider extends SearchRecentSuggestionsProvider {
    +    public final static String AUTHORITY = "my.package.MySuggestionProvider";
    +    public final static int MODE = DATABASE_MODE_QUERIES;
    +
    +    public MySuggestionProvider() {
    +        setupSuggestions(AUTHORITY, MODE);
    +    }
    +}
    +
    + +

    The call to {@link android.content.SearchRecentSuggestionsProvider#setupSuggestions(String,int)} +passes the name of the search authority (matching the one in the searchable configuration) and a +database mode. The database mode must include {@link +android.content.SearchRecentSuggestionsProvider#DATABASE_MODE_QUERIES} and can optionally include +{@link +android.content.SearchRecentSuggestionsProvider#DATABASE_MODE_2LINES}, which will add another column +to the suggestions table that allows you to provide a second line of text with each suggestion. For +example:

    +
    +public final static int MODE = DATABASE_MODE_QUERIES | DATABASE_MODE_2LINES;
    +
    + +

    In the following section, you'll see how to save both lines of text.

    + +

    Now simply declare the content provider in your application manifest with the same authority +string used in the class (and in the searchable configuration). For example:

    + +
    +<application>
    +    <provider android:name=".MySuggestionProvider"
    +              android:authorities="my.package.authority" />
    +    ...
    +</application>
    +
    + + +

    Saving queries

    + +

    In order to populate your collection of recent queries, you need to add each query +received by your searchable Activity to the content provider you've just built. To do this, create +an instance of {@link +android.provider.SearchRecentSuggestions} and call {@link +android.provider.SearchRecentSuggestions#saveRecentQuery(String,String)} each time your searchable +Activity receives a query. For example, here's how you can save the query during your +Activity's {@link android.app.Activity#onCreate(Bundle) onCreate()} method:

    + +
    +@Override
    +public void onCreate(Bundle savedInstanceState) {
    +    super.onCreate(savedInstanceState);
    +    setContentView(R.layout.main);
    +
    +    Intent Intent  = getIntent();
    +
    +    if (Intent.ACTION_SEARCH.equals(Intent .getAction())) {
    +        String query = Intent .getStringExtra(SearchManager.QUERY);
    +        SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
    +                MySuggestionProvider.AUTHORITY, MySuggestionProvider.MODE);
    +        suggestions.saveRecentQuery(query, null);
    +    }
    +}
    +
    + +

    Notice that the {@link android.content.SearchRecentSuggestionsProvider} constructor requires the +same authority and database mode declared by your content provider.

    + +

    The {@link android.provider.SearchRecentSuggestions#saveRecentQuery(String,String)} method takes +the search query string as the first parameter and, optionally, a second string to include as the +second line of the suggestion. The second parameter is only used if you've enabled two-line mode +for the search suggestions with {@link +android.content.SearchRecentSuggestionsProvider#DATABASE_MODE_2LINES}. If you have enabled +two-line mode, then the query text will be matched against this second line as well.

    + +

    That's all that's needed to build a recent queries suggestion provider. However, there's one +other important thing to do: provide the ability for the user to clear this search history.

    + + +

    Clearing the suggestion data

    + +

    To protect the user's privacy, you should always provide a way for the user to clear the recent +query suggestions. To clear the recent queries, simply call {@link +android.provider.SearchRecentSuggestions#clearHistory()}. For example:

    + +
    +SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
    +        HelloSuggestionProvider.AUTHORITY, HelloSuggestionProvider.MODE);
    +suggestions.clearHistory();
    +
    + +

    Simply execute this from your choice of a "Clear Search History" menu item, +preference item, or button. You should also provide a confirmation dialog when this is pressed, to +verify that the user wants to delete their search history.

    + diff --git a/docs/html/guide/topics/search/index.jd b/docs/html/guide/topics/search/index.jd new file mode 100644 index 0000000000000..b2252bbf855eb --- /dev/null +++ b/docs/html/guide/topics/search/index.jd @@ -0,0 +1,111 @@ +page.title=Search +@jd:body + +
    +
    +

    Topics

    +
      +
    1. Using the Android Search Dialog
    2. +
    3. Adding Recent Query Suggestions
    4. +
    5. Adding Custom Suggestions
    6. +
    +

    Reference

    +
      +
    1. Searchable Configuration
    2. +
    +

    See also

    +
      +
    1. Searchable +Dictionary sample app
    2. +
    +
    +
    + + +

    The ability to search is considered to be a core user feature on Android. The user should be able +to search any data that is available to them, whether the content is located on the device or the +Internet. This experience should be seamless and consistent across the entire +system, which is why Android provides a simple search framework to help you provide users with +a familiar search dialog and a great search experience.

    + + + +

    Android's search framework provides a user interface in which the user can perform a search and +an interaction layer that communicates with your application. This way, you don't have to build +a search box that the user must find in order to begin a search. Instead, +a custom search dialog will appear at the top of the screen at the user's command. +The search framework will manage the search dialog and when the user executes their search, the +search framework will pass the query text to your application so that your application can begin a +search. The screenshot to the right shows an example of the search dialog (using +search suggestions).

    + +

    Once your application is set up to use the search dialog, you can:

    + + + +

    The following documents will teach you how to use the search dialog in +your application:

    + +
    +
    Using the Android Search Dialog
    +
    How to set up your application to use the search dialog for searches.
    +
    Adding Recent Query +Suggestions
    +
    How to show suggestions based on queries previously used in the search dialog.
    +
    Adding Custom Suggestions
    +
    How to show suggestions based on custom data from your application and offer your suggestions +in the system-wide Quick Search Box.
    +
    + +

    Also, the Searchable Configuration document +provides a reference for the searchable configuration file (though the above +documents also discuss the configuration file in terms of specific behaviors).

    + +

    Note: The search framework does not provide APIs to +perform searches on your data. Performing actual searches is a task that you must accomplish +using APIs appropriate for your data, such as those in {@link android.database.sqlite} +if your data is in an SQLite database.

    + + +

    Protecting User Privacy

    + +

    When you implement search in your application, you should take steps to protect the user's +privacy whenever possible. Many users consider their activities on the phone, including searches, to +be private information. To protect the user's privacy, you should abide by the following +principles:

    + + + + diff --git a/docs/html/guide/topics/search/search-dialog.jd b/docs/html/guide/topics/search/search-dialog.jd new file mode 100644 index 0000000000000..718668cd08d70 --- /dev/null +++ b/docs/html/guide/topics/search/search-dialog.jd @@ -0,0 +1,542 @@ +page.title=Using the Android Search Dialog +parent.title=Search +parent.link=index.html +@jd:body + +
    +
    +

    Key classes

    +
      +
    1. {@link android.app.SearchManager}
    2. +
    +

    In this document

    +
      +
    1. The Basics
    2. +
    3. Creating a Searchable Configuration
    4. +
    5. Creating a Searchable Activity +
        +
      1. Declaring a searchable Activity
      2. +
      3. Performing a search
      4. +
      +
    6. +
    7. Invoking the Search Dialog +
        +
      1. The impact of the search dialog on your Activity life-cycle
      2. +
      +
    8. +
    9. Passing Search Context Data
    10. +
    11. Adding Voice Search
    12. +
    +

    See also

    +
      +
    1. Adding Recent Query Suggestions
    2. +
    3. Adding Custom Suggestions
    4. +
    5. Searchable Configuration
    6. +
    7. Searchable +Dictionary App
    8. +
    +
    +
    + +

    When you want to provide search in your application, the last thing you should have to worry +about is where to put your search box. By using the Android search framework, your application will +reveal a custom search dialog whenever the user requests it. At the +press of a dedicated search key or an API call from your application, the search dialog will +appear at the top of the screen and will automatically show your application icon. An example is +shown in the screenshot below.

    + +

    This guide will teach you how to set up your application to provide search in a custom search +dialog. In doing so, you will provide a standardized search experience and be able to add +features like voice search and search suggestions.

    + + +

    The Basics

    + + + +

    The Android search framework will manage the search dialog on your behalf; you never need +to draw it or worry about where it is, and your current Activity will not be +interrupted. The {@link android.app.SearchManager} is the component that does this work for +you (hereafter, referred to as "the Search Manager"). It manages the life of the Android search +dialog and will send your application the search query when executed by the user.

    + +

    When the user executes a search, the Search Manager will use a specially-formed Intent to pass +the search query to the Activity that you've declared to handle searches. Essentially, all you +need is an Activity that receives this Intent, performs the search, and presents the results. +Specifically, what you need is the following:

    + +
    +
    A searchable configuration
    +
    This is an XML file that configures the search dialog and includes settings for +features such as the hint text shown in text box and settings voice search and search +suggestion.
    +
    A searchable Activity
    +
    This is the {@link android.app.Activity} that receives the search query then +searches your data and displays the search results.
    +
    A mechanism by which the user can invoke search
    +
    By default, the device search key (if available) will invoke the search dialog once +you've configured a searchable Activity. However, you should always provide another means by +which the user can invoke a search, such as with a search button in the Options Menu or elsewhere in +the Activity UI, because not all devices provide a dedicated search key.
    +
    + + +

    Creating a Searchable Configuration

    + +

    The searchable configuration is an XML file that defines several settings for the Android search +dialog in your application. This file is traditionally named {@code searchable.xml} and must be +saved in the {@code res/xml/} project directory.

    + +

    The file must consist of the {@code <searchable>} element as the root node and specify one +or more attributes that configure your search dialog. For example:

    + +
    +<?xml version="1.0" encoding="utf-8"?>
    +<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    +    android:label="@string/app_label" >
    +</searchable>
    +
    + +

    This is the minimum configuration required in order to provide the search dialog. The {@code +android:label} attribute is the only required attribute and points to a string resource, which +should normally be the same as the application. (Although it's required, this +label isn't actually shown to the user until you enable suggestions for Quick Search Box.)

    + +

    There are several other attributes accepted by the {@code <searchable>} element. Most of +which apply only when configuring features such as search suggestions and voice +search. However, we recommend that you always include the {@code android:hint} attribute, which +specifies a string resource for the text to display in the search dialog's text box before the user +enters their query—it provides important clues to the user about what they can search.

    + +

    Tip: For consistency among other +Android applications, you should format the string for {@code android:hint} as "Search +<content-or-product>". For example, "Search songs and artists" or "Search +YouTube".

    + +

    Next, you'll hook this configuration into your application.

    + + +

    Creating a Searchable Activity

    + +

    When the user executes a search from the search dialog, the Search Manager will send +your searchable {@link android.app.Activity} the search query with the {@link +android.content.Intent#ACTION_SEARCH} {@link android.content.Intent}. Your searchable Activity will +then search your data and present the results.

    + + +

    Declaring a searchable Activity

    + +

    If you don't have one already, create an {@link android.app.Activity} that will be used to +perform searches, then declare it to +accept the {@link android.content.Intent#ACTION_SEARCH} {@link android.content.Intent} and apply the +searchable configuration. To do so, you need to add an {@code +<intent-filter>} element and a {@code <meta-data>} element to the +appropriate {@code <activity>} element in your manifest file. For example:

    + +
    +<application ... >
    +    <activity android:name=".MySearchableActivity" >
    +        <intent-filter>
    +            <action android:name="android.intent.action.SEARCH" />
    +        </intent-filter>
    +        <meta-data android:name="android.app.searchable"
    +                   android:resource="@xml/searchable"/>
    +    </activity>
    +    ...
    +</application>
    +
    + +

    The {@code android:name} attribute in the {@code <meta-data>} element must be defined with +{@code "android.app.searchable"} and the {@code android:resource} attribute value must be a +reference to the searchable configuration file saved in {@code res/xml} (in this example, it +refers to the {@code res/xml/searchable.xml} file).

    + +

    If you're wondering why the {@code +<intent-filter>} does not include a {@code <category>} with the {@code DEFAULT} +value, it's because the Intent that is delivered to this Activity when a search is executed will +explicitly define this Activity as the component for the Intent (which the Search Manager knows +from the searcahble meta-data declared for the Activity).

    + +

    Be aware that the search dialog will not be available from within every +Activity of your application, by default. Rather, the search dialog will be presented to +users only when they +invoke search from a searchable context of your application. A searchable context is any Activity +for which you have +declared searchable meta-data in the manifest file. For example, the searchable Activity itself +(declared in the manifest snippet above) is +a searchable context because it contains searchable meta-data that defines the +searchable configuration. Any other Activity in your application is not a searchable context, by +default, and thus, will not reveal the search dialog. You probably do want the +search dialog to be available from every Activity in your application, so this can be easily +fixed.

    + +

    If you want all of your activities to provide the search dialog, add another {@code +<meta-data>} element inside the {@code +<application>} element. Use this element to declare the existing searchable Activity as the +default searchable Activity. For example:

    + +
    +<application ... >
    +    <activity android:name=".MySearchableActivity" >
    +        <intent-filter>
    +            <action android:name="android.intent.action.SEARCH" />
    +        </intent-filter>
    +        <meta-data android:name="android.app.searchable"
    +                   android:resource="@xml/searchable"/>
    +    </activity>
    +    <activity android:name=".AnotherActivity" ... >
    +    </activity>
    +    <!-- this one declares the searchable Activity for the whole app -->
    +    <meta-data android:name="android.app.default_searchable"
    +               android:value=".MySearchableActivity" />
    +    ...
    +</application>
    +
    + +

    The {@code <meta-data>} element with the {@code android:name} attribute value of +{@code "android.app.default_searchable"} specifies a default searchable Activity for the context in +which it is placed (which, in this case, is the entire application). The searchable Activity to +use is specified with the {@code android:value} attribute. All other activities in the +application, such as {@code AnotherActivity}, are now considered a searchable context and can invoke +the search dialog. When a search is executed, {@code MySearchableActivity} will +be launched to handle the search query.

    + +

    Notice that this allows you to control which activities provide search at a more granular level. +To specify only an individual Activity as a searchable context, simply place the {@code +<meta-data>} with the {@code +"android.app.default_searchable"} name inside the respective {@code <activity>} +element (rather than inside the {@code <application>}). And, while it is uncommon, you can +even create more than one searchable Activity and provide each one in different contexts of your +application, either by declaring a different searchable Activity in each {@code <activity>} +element, or declaring a default searchable Activity for the entire application and then overriding +it with a different {@code <meta-data>} element inside certain activities.

    + + +

    Performing a search

    + +

    Once your Activity is declared searchable, performing the actual search involves three steps: +receiving the query, searching your data, and presenting the results.

    + +

    Traditionally, your search results should be presented in a {@link android.widget.ListView} +(assuming that our results are text-based), so +you may want your searchable Activity to extend {@link android.app.ListActivity}, which +provides easy access to {@link android.widget.ListView} APIs. (See the List View Tutorial for a simple +{@link android.app.ListActivity} sample.)

    + + +

    Receiving the query

    + +

    When a search is executed from the search dialog, your searchable Activity will be opened +with the {@link android.content.Intent#ACTION_SEARCH} {@link android.content.Intent}, which carries +the search query in the +{@link android.app.SearchManager#QUERY QUERY} extra. All you need to do is check for +this Intent and extract the string. For example, here's how you can get the query when your +Activity launches:

    + +
    +@Override
    +public void onCreate(Bundle savedInstanceState) {
    +    super.onCreate(savedInstanceState);
    +    setContentView(R.layout.search);
    +
    +    Intent intent = getIntent();
    +
    +    if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
    +      String query = intent.getStringExtra(SearchManager.QUERY);
    +      doMySearch(query);
    +    }
    +}
    +
    + +

    The {@link android.app.SearchManager#QUERY QUERY} string is always included with +the {@link android.content.Intent#ACTION_SEARCH} Intent. In this example, the query is +retrieved and passed to a local {@code doMySearch()} method where the actual search operation +is done.

    + + +

    Searching your data

    + +

    The process of storing and searching your data is a process that's unique to your application. +There are many ways that you might do this and discussing all options is beyond the scope of +this document. This guide will not teach you how to store your data and search it; this +is something you must carefully consider in terms of your needs and your data. However, here are +some tips you may be able to apply:

    + + + + + + +

    Regardless of where your data lives and how you search it, we recommend that you return search +results to your searchable Activity with an {@link android.widget.Adapter}. This way, you can easily +present all the search results in a {@link android.widget.ListView}. If your data comes from a +SQLite database query, then you can easily apply your results to a {@link android.widget.ListView} +using a {@link android.widget.CursorAdapter}. If your data comes in some other type of format, then +you can create an extension of the {@link android.widget.BaseAdapter}.

    + +

    Presenting the results

    + +

    Presenting your search results is mostly a UI detail and not something covered by the search +framework APIs. However, a simple solution is to create your searchable Activity to extend {@link +android.app.ListActivity} and then call {@link +android.app.ListActivity#setListAdapter(ListAdapter)}, passing it an {@link +android.widget.Adapter} that is bound to your data. This will automatically project all the +results into the Activity {@link android.widget.ListView}.

    + +

    For more help presenting your results, see the {@link android.app.ListActivity} +documentation.

    + +

    Also see the Searchable Dictionary sample +application for an a complete demonstration of how to search an SQLite database and use an +{@link android.widget.Adapter} to provide resuls in a {@link android.widget.ListView}.

    + + +

    Invoking the Search Dialog

    + +

    Once you have a searchable Activity in place, invoking the search dialog so the user can +submit a +query is easy. Many Android devices provide a dedicated search key and when it is pressed while the +user is within a searchable context of your application, the search dialog will be revealed. +However, +you should never assume that a search key is available on the user's device and should always +provide a search button in your UI that will invoke search.

    + +

    To invoke search from your Activity, simply call {@link +android.app.Activity#onSearchRequested()}.

    + +

    For example, you should provide a menu item in your Options Menu or a button in your UI to +invoke search with this method. For your convenience, this search_icons.zip file includes icons for +medium and high density screens, which you can use for your menu item or button (low density +screens will automatically scale-down the hdpi image by one half).

    + + + +

    You can also enable "type-to-search" functionality in your Activity by calling {@link +android.app.Activity#setDefaultKeyMode(int) setDefaultKeyMode}({@link +android.app.Activity#DEFAULT_KEYS_SEARCH_LOCAL}). When this is enabled and the user begins typing on +the keyboard, search will automatically be +invoked and the keystrokes will be inserted in the search dialog. Be sure to enable this mode +during your Activity {@link android.app.Activity#onCreate(Bundle) onCreate()} method.

    + + +

    The impact of the search dialog on your Activity life-cycle

    + +

    The search dialog behaves like a {@link android.app.Dialog} that floats at the top of the +screen. It +does not cause any change in the Activity stack, so no life-cycle methods (such as {@link +android.app.Activity#onPause()}) will +be called. All that happens is your Activity loses input focus as it is given to the search dialog. +

    + +

    If you want to be notified when search is invoked, simply override the {@link +android.app.Activity#onSearchRequested()} method. When this is called, you can do any work you may +want to do when your Activity looses input focus (such as pause animations). But unless you are +Passing Search Context Data (discussed above), you should always +call the super class implementation. For example:

    + +
    +@Override
    +public boolean onSearchRequested() {
    +    pauseSomeStuff();
    +    return super.onSearchRequested();
    +}
    +
    + +

    If the user cancels search by pressing the device Back key, the Activity in which search was +invoked will re-gain input focus. You can register to be notified when the search dialog is +closed with {@link android.app.SearchManager#setOnDismissListener(SearchManager.OnDismissListener)} +and/or {@link android.app.SearchManager#setOnCancelListener(SearchManager.OnCancelListener)}. You +should normally only need to register the {@link android.app.SearchManager.OnDismissListener +OnDismissListener}, because this is called every time that the search dialog is closed. The {@link +android.app.SearchManager.OnCancelListener OnCancelListener} only pertains to events in which the +user explicitly left the search dialog, so it is not called when a search is executed (in which +case, the search dialog naturally disappears).

    + +

    If the current Activity is not the searchable Activity, then the normal Activity life-cycle +events will be triggered once the user executes a search (the current Activity will receive {@link +android.app.Activity#onPause()} and so forth, as +described in Application +Fundamentals). If, however, the current Activity is the searchable Activity, then one of two +things will happen:

    + + + +

    This second scenario is normally ideal, because the chances are good that once a search is +completed, the user will perform additional searches and it's a bad experience if your application +piles multiple instances of the searchable Activity on the stack. So we recommend that you set your +searchable Activity to "singleTop" launch mode in the application manifest. For example:

    + +
    +<activity android:name=".MySearchableActivity"
    +              android:launchMode="singleTop" >
    +    <intent-filter>
    +        <action android:name="android.intent.action.SEARCH" />
    +    </intent-filter>
    +    <meta-data android:name="android.app.searchable"
    +                      android:resource="@xml/searchable"/>
    +  </activity>
    +
    + + +

    Passing Search Context Data

    + +

    In order to refine your search criteria, you may want to provide some additional +data to your searchable Activity when a search is executed. For instance, when you search your data, +you may want to filter results based on more than just the search query text. In a simple +case, you could just make your refinements inside the searchable Activity, for every search made. +If, however, your +search criteria may vary from one searchable context to another, then you can pass whatever data is +necessary to refine your search in the {@link android.app.SearchManager#APP_DATA} Bundle, which is +included in the {@link android.content.Intent#ACTION_SEARCH} Intent.

    + +

    To pass this kind of data to your searchable Activity, you need to override {@link +android.app.Activity#onSearchRequested()} method for the Activity in which search will be invoked. +For example:

    + +
    +@Override
    +public boolean onSearchRequested() {
    +     Bundle appData = new Bundle();
    +     appData.putBoolean(MySearchableActivity.JARGON, true);
    +     startSearch(null, false, appData, false);
    +     return true;
    + }
    +
    + +

    Returning "true" indicates that you have successfully handled this callback event. Then in your +searchable Activity, you can extract this data from the {@link +android.app.SearchManager#APP_DATA} {@link android.os.Bundle} to refine the search. For example:

    + +
    + Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);
    + if (appData != null) {
    +     boolean jargon = appData.getBoolean(MySearchableActivity.JARGON);
    + }
    +
    + +

    Note: You should never call the {@link +android.app.Activity#startSearch(String,boolean,Bundle,boolean) startSearch()} method from outside +the {@link android.app.Activity#onSearchRequested()} callback method. When you want to invoke the +search dialog, always call {@link android.app.Activity#onSearchRequested()} so that custom +implementations (such as the addition of {@code appData}, in the above example) can be accounted +for.

    + + +

    Adding Voice Search

    + +

    You can easily add voice search functionality to your search dialog by adding the {@code +android:voiceSearchMode} attribute to your searchable configuration. This will add a voice search +button in the search dialog that, when clicked, will launch a voice prompt. When the user +has finished speaking, the transcribed search query will be sent to your searchable +Activity.

    + +

    To enable voice search for your activity, add the {@code android:voiceSearchMode} +attribute to your searchable configuration. For example:

    + +
    +<?xml version="1.0" encoding="utf-8"?>
    +<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    +    android:label="@string/search_label"
    +    android:hint="@string/search_hint"
    +    android:voiceSearchMode="showVoiceSearchButton|launchRecognizer" >
    +</searchable>
    +
    + +

    The value {@code showVoiceSearchButton} is required to enable voice +search, while the second value, {@code launchRecognizer}, specifies that the voice search button +should launch a recognizer that returns the transcribed text to the searchable Activity. This is +how most applications should declare this attribute.

    + +

    There are some additional attributes you can provide to specify the voice search behavior, such +as the language to be expected and the maximum number of results to return. See the Searchable Configuration for more information about the +available attributes.

    + +

    Note: Carefully consider whether voice search is appropriate for +your application. All searches performed with the voice search button will be immediately sent to +your searchable Activity without a chance for the user to review the transcribed query. Be sure to +sufficiently test the voice recognition and ensure that it understands the types of queries that +the user will submit inside your application.

    diff --git a/docs/html/guide/topics/search/searchable-config.jd b/docs/html/guide/topics/search/searchable-config.jd new file mode 100644 index 0000000000000..f3a5bb1b6721c --- /dev/null +++ b/docs/html/guide/topics/search/searchable-config.jd @@ -0,0 +1,356 @@ +page.title=Searchable Configuration +parent.title=Search +parent.link=index.html +@jd:body + +
    +
    +

    See also

    +
      +
    1. Using the Android Search Dialog
    2. +
    3. Adding Recent Query Suggestions
    4. +
    5. Adding Custom Suggestions
    6. +
    +
    +
    + +

    In order to utilize the Android search framework and provide a custom search dialog, your +application must provide a search +configuration in the form of an XML resource. This document describes the search configuration XML +in terms of its syntax and usage. For a more complete discussion about how to implement search +features for your application, see the companion documents about Search.

    + +
    + +
    file location:
    +
    res/xml/filename.xml
    +The filename will be used as the resource ID.
    + +
    syntax:
    +
    +
    +<?xml version="1.0" encoding="utf-8"?>
    +<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    +    android:label="string resource"
    +    android:hint="string resource"
    +    android:searchMode=["queryRewriteFromData" | "queryRewriteFromText"]
    +    android:searchButtonText="string resource"
    +    android:inputType="{@link android.R.attr#inputType}"
    +    android:imeOptions="{@link android.R.attr#imeOptions}"
    +    android:searchSuggestAuthority="string"
    +    android:searchSuggestPath="string"
    +    android:searchSuggestSelection="string"
    +    android:searchSuggestIntentAction="string"
    +    android:searchSuggestIntentData="string"
    +    android:searchSuggestThreshold="int"
    +    android:includeInGlobalSearch=["true" | "false"]
    +    android:searchSettingsDescription="string resource"
    +    android:queryAfterZeroResults=["true" | "false"]
    +    android:voiceSearchMode=["showVoiceSearchButton" | "launchWebSearch" | "launchRecognizer"]
    +    android:voiceLanguageModel=["free-form" | "web_search"]
    +    android:voicePromptText="string resource"
    +    android:voiceLanguage="string"
    +    android:voiceMaxResults="int"
    +    >
    +    <actionkey
    +        android:keycode="{@link android.view.KeyEvent KEYCODE}"
    +        android:queryActionMsg="string"
    +        android:suggestActionMsg="string"
    +        android:suggestActionMsgColumn="string" >
    +</searchable>
    +
    +
    + +
    elements:
    +
    +
    +
    <searchable>
    +
    Defines all search configurations used with the search dialog. +

    attributes:

    +
    +
    android:label
    +
    String resource. Required. This is the name of your application. +It should normally be the same as the name applied to the {@code android:label} attribute of your {@code <activity>} or +{@code +<application>} manifest element. This is only visible to the user when you set +android:includeInGlobalSearch "true", in which case, this label is used to identify +your application as a searchable item in the system's search settings.
    +
    android:hint
    +
    String resource. The text to display in the search text field when no text has + been entered. This is recommended in order to provide a hint to the user about what +content is searchable. For consistency among other Android applications, you should format the +string for {@code android:hint} as "Search <content-or-product>". For example, +"Search songs and artists" or "Search YouTube".
    +
    android:searchMode
    +
    Keyword. Sets additional modes that control the search presentation. +Specifically, the available modes define how the query text in the search dialog's text box +should be rewritten when a suggestion is focused. The following mode values are accepted: + + + + + + + + + + +
    ValueDescription
    "queryRewriteFromData"If set, this causes the suggestion column + {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} to be considered as the +text for suggestion query + rewriting. This should only be used when the values in + {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} are suitable for user +inspection and editing - + typically, HTTP/HTTPS Uri's.
    "queryRewriteFromText"If set, this causes the suggestion + column {@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1} to be considered as the +text for suggestion query + rewriting. This should be used for suggestions in which no query + text is provided and the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} +values are not suitable + for user inspection and editing.
    +

    For more information, see the discussion about rewriting the query text in Adding Custom Suggestions.

    +
    +
    android:searchButtonText
    +
    String resource. The text to display in the button that executes the search. By +default, the button shows a search icon (a magnifying glass), which is ideal for +internationalization.
    +
    android:inputType
    +
    Keyword. Defines the type of input method (soft-keyboard) to use with the search +dialog. For most searches, in which free form text is expected, this attribute is not needed and +the default input method should be used. See {@link android.R.attr#inputType} for a list of suitable +values for this attribute.
    +
    android:imeOptions
    +
    Keyword. Supplies additional options for the input method. + For most searches, in which free form text is expected, this attribute is not needed, + and will default to "actionSearch" (provides the "search" button instead of a carriage +return). See {@link android.R.attr#imeOptions} for a list of suitable values for this attribute. +
    +
    + +

    If you have defined a content provider to generate search suggestions, you need to + define additional attributes in order to configure communications with the Content + Provider. When providing search suggestions, you'll need some of the following + {@code <searchable>} attributes:


    + +
    +
    android:searchSuggestAuthority
    +
    String. Required to provide search suggestions. + This value must match the authority string provided in the {@code android:authorities} +attribute of the {@code <provider>} element.
    +
    android:searchSuggestPath
    +
    String. This path will be used as a portion of the suggestions + query {@link android.net.Uri}, after the prefix and authority, but before +the standard suggestions path. + This is only required if you have a single content provider issuing different types + of suggestions (e.g. for different data types) and you need + a way to disambiguate the suggestions queries when they are received.
    +
    android:searchSuggestSelection
    +
    String. This value will be passed into your + query function as the {@code selection} parameter. Typically this will be a WHERE clause +for your database, and should contain a single question mark, which is a place-holder for the +actual query string that has been typed by the user. However, you can also use any non-null +value to simply trigger the delivery of the query text via the {@code +selectionArgs} parameter (and then ignore the {@code selection} parameter).
    +
    android:searchSuggestIntentAction
    +
    String. The default Intent action to be used when a user + clicks on a search suggestion (such as {@code "android.intent.action.VIEW"}). + If not overridden by the selected suggestion (via the {@link +android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column), this value will + be placed in the action field of the {@link android.content.Intent} when the + user clicks a suggestion.
    +
    android:searchSuggestIntentData
    +
    String. The default Intent data to be used when a user + clicks on a search suggestion. + If not overridden by the selected suggestion (via the {@link +android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column), this value will be + placed in the data field of the {@link android.content.Intent} when the user clicks + a suggestion.
    +
    android:searchSuggestThreshold
    +
    Integer. The minimum number of characters needed to + trigger a suggestion look-up. Only guarantees that a source will not be + queried for anything shorter than the threshold. The default value is 0.
    +
    + +

    For more information about the above attributes for search suggestions, see the guides for + Adding Recent Query Suggestions and + Adding Custom Suggestions.

    + +

    Beyond providing search suggestions while using your application's search dialog, you + can also configure your search suggestions to be made available to Quick Search Box, + which will allow users so receive search suggestions from your application content from outside + your application. When providing search suggestions to Quick Search Box, you'll need some of the + following {@code <searchable>} attributes:


    + +
    +
    android:includeInGlobalSearch
    +
    Boolean. Required to provide search suggestions in + Quick Search Box. "true" if you want your suggestions to be + included in the globally accessible Quick Search Box. Note that the user must + still enable your application as a searchable item in the system search settings in order + for your suggestions to appear in Quick Search Box.
    +
    android:searchSettingsDescription
    +
    String. Provides a brief description of the search suggestions that you provide +to Quick Search Box, which will be displayed in the searchable items entry for your application. +Your description should concisely describe the content that is searchable. For example, "Artists, +albums, and tracks" for a music application, or "Saved notes" for a notepad application.
    +
    android:queryAfterZeroResults
    +
    Boolean. "true" if you want your content provider to be invoked for + supersets of queries that have returned zero results for in the past. For example, if a + source returned zero results for "bo", it would be ignored for "bob". If "false", + this source will only be ignored for a single session; the next time the search dialog + is invoked, all sources will be queried. The default value is false.
    +
    + +

    To enable voice search for your search dialog, you'll need some of the + following {@code <searchable>} attributes:


    + +
    +
    android:voiceSearchMode
    +
    Keyword. Required to provide voice search capabilities. + Enables voice search for the search dialog, with a specific mode for voice search. + (Voice search may not be provided by the device, in which case these flags will + have no effect.) The following mode values are accepted: + + + + + + + + + + + + + + +
    ValueDescription
    "showVoiceSearchButton"Display a voice search button. This only + takes effect if voice search is available on the device. If set, then either + {@code "launchWebSearch"} or {@code "launchRecognizer"} must also be set + (separated by the pipe | character).
    "launchWebSearch"The voice search button will take the user directly + to a built-in voice web search activity. Most applications will not use this flag, as + it will take the user away from the Activity in which search was invoked.
    "launchRecognizer"The voice search button will take + the user directly to a built-in voice recording activity. This Activity + will prompt the user to speak, transcribe the spoken text, and forward the resulting + query text to the searchable Activity, just as if the user had typed it into the + search UI and clicked the search button.
    +
    +
    android:voiceLanguageModel
    +
    Keyword. The language model that + should be used by the voice recognition system. The following values are accepted: + + + + + + + + + + +
    ValueDescription
    "free_form"Use a language model based on free-form speech recognition. This is the +default.
    "web_search"Use a language model based on web search terms.
    +

    Also see + {@link android.speech.RecognizerIntent#EXTRA_LANGUAGE_MODEL} for more + information.

    +
    android:voicePromptText
    +
    String. An additional message to display in the voice input dialog.
    +
    android:voiceLanguage
    +
    String. The spoken language to be expected, expressed as the string value of +a constants in {@link java.util.Locale} (for example, {@code "de"} for German or {@code "fr"} for +French). This is only needed if it is different from the current value of {@link +java.util.Locale#getDefault() Locale.getDefault()}.
    +
    android:voiceMaxResults
    +
    Integer. Forces the maximum number of results to return, + including the "best" result which will always be provided as the {@link +android.content.Intent#ACTION_SEARCH} Intent's primary + query. Must be 1 or greater. Use {@link android.speech.RecognizerIntent#EXTRA_RESULTS} to +get the results from the Intent. + If not provided, the recognizer will choose how many results to return.
    +
    +
    + + +
    <actionkey>
    +
    Defines a shortcut key for a search action, in order to provide special behaviors at the touch +of a button, based on the current query or selected suggestion. ​For example, the Contacts +application enables the device call key for suggestions. So, when +the user focuses on a search suggestion using the directional controls and then presses the call +key, the application will immediately initiate a phone call to the suggested contact. See the +{@link android.app.SearchManager} for more information about action keys. +

    attributes:

    +
    +
    android:keycode
    +
    String. Required. A key code from {@link +android.view.KeyEvent} that represents the action key + you wish to respond to (for example {@code "KEYCODE_CALL"}). This will be added to the + {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} Intent that is passed to your + searchable Activity. To examine the key code, use + {@link android.content.Intent#getIntExtra getIntExtra(SearchManager.ACTION_KEY)}. + In addition to the key code, you must also provide one or more of + the action specifier attributes below. Not all action keys +are actually supported using this mechanism, as many of them are used for typing, + navigation, or system functions. Note that although each of the action message elements are +optional, at least one must be present for the action key to have any effect.
    +
    android:queryActionMsg
    +
    String. An action message to be sent if the action key is pressed while the +user is simply entering query text. This will be added to the + {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} Intent that is + passed to your searchable Activity. To examine the string, use + {@link android.content.Intent#getStringExtra + getStringExtra(SearchManager.ACTION_MSG)}.
    +
    android:suggestActionMsg
    +
    String. An action message to be sent if the action key is pressed while a + suggestion is being displayed and is currently selected. This will be added to the + Intent that is passed to your searchable Activity (using the action you've defined for + suggestions). To examine the string, + use {@link android.content.Intent#getStringExtra + getStringExtra(SearchManager.ACTION_MSG)}. Note that this should only be used if all your +suggestions support this action key. If not all suggestions can handle the same action key, then +you must instead use the following {@code android:suggestActionMsgColumn} attribute.
    +
    android:suggestActionMsgColumn
    +
    String. The name of the column in your content provider that defines the +action message for this action key, which is to be sent if the action key is pressed while a + suggestion is being displayed and is currently selected. This attribute lets you control the +action key on a suggestion-by-suggestion basis, because, instead of using the {@code +android:suggestActionMsg} attribute to define the action message for all suggestions, each entry in +your content provider provides its own action message. First, you must define a column in your +content provider for each suggestion to provide an action message, then provide the name of that +column in this attribute. The search manager will look at your suggestion cursor, + using the string provided here in order to select your action message column, and + then select the action message string from the cursor. That string will be added to the + Intent that is passed to your searchable Activity (using the action you've defined for + suggestions). To examine the string, use {@link +android.content.Intent#getStringExtra getStringExtra(SearchManager.ACTION_MSG)}. If the data +does not exist for the selected suggestion, the action key will be ignored.
    +
    +
    +
    +
    + + +
    example:
    +
    XML file saved at res/xml/searchable.xml: +
    +<?xml version="1.0" encoding="utf-8"?>
    +<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    +    android:label="@string/search_label"
    +    android:hint="@string/search_hint"
    +    android:searchSuggestAuthority="dictionary"
    +    android:searchSuggestIntentAction="android.intent.action.VIEW"
    +    android:includeInGlobalSearch="true"
    +    android:searchSettingsDescription="@string/settings_description" >
    +</searchable>
    +
    + +
    + + +
    + + + + diff --git a/docs/html/images/search/search-suggest-custom.png b/docs/html/images/search/search-suggest-custom.png new file mode 100644 index 0000000000000..be14219d3b8f1 Binary files /dev/null and b/docs/html/images/search/search-suggest-custom.png differ diff --git a/docs/html/images/search/search-suggest-recent-queries.png b/docs/html/images/search/search-suggest-recent-queries.png new file mode 100644 index 0000000000000..869edf28c8717 Binary files /dev/null and b/docs/html/images/search/search-suggest-recent-queries.png differ diff --git a/docs/html/images/search/search-ui.png b/docs/html/images/search/search-ui.png new file mode 100644 index 0000000000000..19ecc198f2aee Binary files /dev/null and b/docs/html/images/search/search-ui.png differ diff --git a/docs/html/shareables/search_icons.zip b/docs/html/shareables/search_icons.zip new file mode 100644 index 0000000000000..bc984655592dd Binary files /dev/null and b/docs/html/shareables/search_icons.zip differ