diff options
author | Robert Ly <robertly@google.com> | 2012-03-15 11:38:49 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2012-03-15 11:38:49 -0700 |
commit | 696c55d40d703a25db1f03742211af58684cb088 (patch) | |
tree | af8eadb9864def9dfa38ccf8c8c696a155348fe8 /docs | |
parent | 6c25ffb77069a9f39884b8e91e1810254c3e2f03 (diff) | |
parent | d01ec4c9afac7984211ec359cf666739df4342a2 (diff) | |
download | frameworks_base-696c55d40d703a25db1f03742211af58684cb088.zip frameworks_base-696c55d40d703a25db1f03742211af58684cb088.tar.gz frameworks_base-696c55d40d703a25db1f03742211af58684cb088.tar.bz2 |
am d01ec4c9: am c3b24faa: am b285125d: Merge "docs: android u search class" into ics-mr1
* commit 'd01ec4c9afac7984211ec359cf666739df4342a2':
docs: android u search class
Diffstat (limited to 'docs')
-rw-r--r-- | docs/html/resources/resources_toc.cs | 20 | ||||
-rw-r--r-- | docs/html/training/search/backward-compat.jd | 87 | ||||
-rw-r--r-- | docs/html/training/search/index.jd | 53 | ||||
-rw-r--r-- | docs/html/training/search/search.jd | 217 | ||||
-rw-r--r-- | docs/html/training/search/setup.jd | 197 |
5 files changed, 574 insertions, 0 deletions
diff --git a/docs/html/resources/resources_toc.cs b/docs/html/resources/resources_toc.cs index 8483037..890f92a 100644 --- a/docs/html/resources/resources_toc.cs +++ b/docs/html/resources/resources_toc.cs @@ -99,6 +99,26 @@ </li> <li class="toggle-list"> + <div><a href="<?cs var:toroot ?>training/search/index.html"> + <span class="en">Adding Search Functionality</span> + </a></div> + <ul> + <li><a href="<?cs var:toroot ?>training/search/setup.html"> + <span class="en">Setting up the Search Interface</span> + </a> + </li> + <li><a href="<?cs var:toroot ?>training/search/search.html"> + <span class="en">Storing and Searching for Data</span> + </a> + </li> + <li><a href="<?cs var:toroot ?>training/search/backward-compat.html"> + <span class="en">Remaining Backward Compatible</span> + </a> + </li> + </ul> + </li> + + <li class="toggle-list"> <div><a href="<?cs var:toroot ?>training/id-auth/index.html"> <span class="en">Remembering Users</span> </a></div> diff --git a/docs/html/training/search/backward-compat.jd b/docs/html/training/search/backward-compat.jd new file mode 100644 index 0000000..de0e3d2 --- /dev/null +++ b/docs/html/training/search/backward-compat.jd @@ -0,0 +1,87 @@ +page.title=Remaining Backward Compatible +trainingnavtop=true +previous.title=Storing and Searching for Data +previous.link=search.html + +@jd:body + + <div id="tb-wrapper"> + <div id="tb"> + <h2>This lesson teaches you to</h2> + + <ul> + <li><a href="{@docRoot}training/search/backward-compat.html#set-sdk">Set Minimum and Target + SDK Values</a></li> + + <li><a href="{@docRoot}training/search/backward-compat.html#provide-sd">Provide the Search + Dialog for Older Devices</a></li> + + <li><a href="{@docRoot}training/search/backward-compat.html#check-ver">Check the Android Build + Version at Runtime</a></li> + </ul> + </div> + </div> + + <p>The {@link android.widget.SearchView} and action bar are only available on Android 3.0 and + later. To support older platforms, you can fall back to the search dialog. The search dialog is a + system provided UI that overlays on top of your application when invoked.</p> + + <h2 id="set-sdk">Set Minimum and Target API levels</h2> + + <p>To setup the search dialog, first declare in your manifest that you want to support older + devices, but want to target Android 3.0 or later versions. When you do this, your application + automatically uses the action bar on Android 3.0 or later and uses the traditional menu system on + older devices:</p> + <pre> +<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="15" /> + +<application> +... +</pre> + + <h2 id="provide-sd">Provide the Search Dialog for Older Devices</h2> + + <p>To invoke the search dialog on older devices, call {@link + android.app.Activity#onSearchRequested onSearchRequested()} whenever a user selects the search + menu item from the options menu. Because Android 3.0 and higher devices show the + {@link android.widget.SearchView} in the action bar (as demonstrated in the first lesson), only versions + older than 3.0 call {@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} when the + user selects the search menu item. + </p> + <pre> +@Override +public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.search: + onSearchRequested(); + return true; + default: + return false; + } +} +</pre> + + <h2 id="check-ver">Check the Android Build Version at Runtime</h2> + + <p>At runtime, check the device version to make sure an unsupported use of {@link + android.widget.SearchView} does not occur on older devices. In our example code, this happens in + the {@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} method:</p> + <pre> +@Override +public boolean onCreateOptionsMenu(Menu menu) { + + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.options_menu, menu); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + SearchManager searchManager = + (SearchManager) getSystemService(Context.SEARCH_SERVICE); + SearchView searchView = + (SearchView) menu.findItem(R.id.search).getActionView(); + searchView.setSearchableInfo( + searchManager.getSearchableInfo(getComponentName())); + searchView.setIconifiedByDefault(false); + } + return true; +} +</pre> diff --git a/docs/html/training/search/index.jd b/docs/html/training/search/index.jd new file mode 100644 index 0000000..bfd1618 --- /dev/null +++ b/docs/html/training/search/index.jd @@ -0,0 +1,53 @@ +page.title=Adding Search Functionality +trainingnavtop=true +startpage=true +next.title=Setting Up the Search Interface +next.link=setup.html + +@jd:body + + <div id="tb-wrapper"> + <div id="tb"> + <h2>Dependencies and prerequisites</h2> + + <ul> + <li>Android 3.0 or later (with some support for Android 2.1)</li> + + <li>Experience building an Android <a href="{@docRoot}guide/topics/ui/index.html">User + Interface</a></li> + </ul> + + <h2>You should also read</h2> + + <ul> + <li><a href="{@docRoot}guide/topics/search/index.html">Search</a></li> + + <li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable + Dictionary Sample App</a></li> + </ul> + </div> + </div> + + <p>Android's built-in search features offer apps an easy way to provide a + consistent search experience for all users. There are two ways to implement search in your app + depending on the version of Android that is running on the device. This class covers how to add + search with {@link android.widget.SearchView}, which was introduced in Android 3.0, while + maintaining backward compatibility with older versions of Android by using the default search + dialog provided by the system.</p> + + <h2>Lessons</h2> + + <dl> + <dt><b><a href="setup.html">Setting Up the Search Interface</a></b></dt> + + <dd>Learn how to add a search interface to your app and how to configure an activity to handle + search queries.</dd> + + <dt><b><a href="search.html">Storing and Searching for Data</a></b></dt> + + <dd>Learn a simple way to store and search for data in a SQLite virtual database table.</dd> + + <dt><b><a href="backward-compat.html">Remaining Backward Compatible</a></b></dt> + + <dd>Learn how to keep search features backward compatible with older devices by using.</dd> + </dl>
\ No newline at end of file diff --git a/docs/html/training/search/search.jd b/docs/html/training/search/search.jd new file mode 100644 index 0000000..17e7640 --- /dev/null +++ b/docs/html/training/search/search.jd @@ -0,0 +1,217 @@ +page.title=Storing and Searching for Data +trainingnavtop=true +previous.title=Setting Up the Search Interface +previous.link=setup.html +next.title=Remaining Backward Compatible +next.link=backward-compat.html + +@jd:body + + <div id="tb-wrapper"> + <div id="tb"> + <h2>This lesson teaches you to</h2> + + <ul> + <li><a href="{@docRoot}training/search/search.html#create">Create the Virtual + Table</a></li> + + <li><a href="{@docRoot}training/search/search.html#populate">Populate the Virtual + Table</a></li> + + <li><a href="{@docRoot}training/search/search.html#search">Search for the Query</a></li> + </ul> + </div> + </div> + + <p>There are many ways to store your data, such as in an online database, in a local SQLite + database, or even in a text file. It is up to you to decide what is the best solution for your + application. This lesson shows you how to create a SQLite virtual table that can provide robust + full-text searching. The table is populated with data from a text file that contains a word and + definition pair on each line in the file.</p> + + <h2 id="create">Create the Virtual Table</h2> + + <p>A virtual table behaves similarly to a SQLite table, but reads and writes to an object in + memory via callbacks, instead of to a database file. To create a virtual table, create a class + for the table:</p> + <pre> +public class DatabaseTable { + private final DatabaseOpenHelper mDatabaseOpenHelper; + + public DatabaseTable(Context context) { + mDatabaseOpenHelper = new DatabaseOpenHelper(context); + } +} +</pre> + + <p>Create an inner class in <code>DatabaseTable</code> that extends {@link + android.database.sqlite.SQLiteOpenHelper}. The {@link android.database.sqlite.SQLiteOpenHelper} class + defines abstract methods that you must override so that your database table can be created and + upgraded when necessary. For example, here is some code that declares a database table that will + contain words for a dictionary app:</p> + <pre> +public class DatabaseTable { + + private static final String TAG = "DictionaryDatabase"; + + //The columns we'll include in the dictionary table + public static final String COL_WORD = "WORD"; + public static final String COL_DEFINITION = "DEFINITION"; + + private static final String DATABASE_NAME = "DICTIONARY"; + private static final String FTS_VIRTUAL_TABLE = "FTS"; + private static final int DATABASE_VERSION = 1; + + private final DatabaseOpenHelper mDatabaseOpenHelper; + + public DatabaseTable(Context context) { + mDatabaseOpenHelper = new DatabaseOpenHelper(context); + } + + private static class DatabaseOpenHelper extends SQLiteOpenHelper { + + private final Context mHelperContext; + private SQLiteDatabase mDatabase; + + private static final String FTS_TABLE_CREATE = + "CREATE VIRTUAL TABLE " + FTS_VIRTUAL_TABLE + + " USING fts3 (" + + COL_WORD + ", " + + COL_DEFINITION + ")"; + + DatabaseOpenHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + mHelperContext = context; + } + + @Override + public void onCreate(SQLiteDatabase db) { + mDatabase = db; + mDatabase.execSQL(FTS_TABLE_CREATE); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + + newVersion + ", which will destroy all old data"); + db.execSQL("DROP TABLE IF EXISTS " + FTS_VIRTUAL_TABLE); + onCreate(db); + } + } +} +</pre> + + <h2 id="populate">Populate the Virtual Table</h2> + + <p>The table now needs data to store. The following code shows you how to read a text file + (located in <code>res/raw/definitions.txt</code>) that contains words and their definitions, how + to parse that file, and how to insert each line of that file as a row in the virtual table. This + is all done in another thread to prevent the UI from locking. Add the following code to your + <code>DatabaseOpenHelper</code> inner class.</p> + + <p class="note"><strong>Tip:</strong> You also might want to set up a callback to notify your UI + activity of this thread's completion.</p> + <pre> +private void loadDictionary() { + new Thread(new Runnable() { + public void run() { + try { + loadWords(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + }).start(); + } + +private void loadWords() throws IOException { + final Resources resources = mHelperContext.getResources(); + InputStream inputStream = resources.openRawResource(R.raw.definitions); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + + try { + String line; + while ((line = reader.readLine()) != null) { + String[] strings = TextUtils.split(line, "-"); + if (strings.length < 2) continue; + long id = addWord(strings[0].trim(), strings[1].trim()); + if (id < 0) { + Log.e(TAG, "unable to add word: " + strings[0].trim()); + } + } + } finally { + reader.close(); + } +} + +public long addWord(String word, String definition) { + ContentValues initialValues = new ContentValues(); + initialValues.put(COL_WORD, word); + initialValues.put(COL_DEFINITION, definition); + + return mDatabase.insert(FTS_VIRTUAL_TABLE, null, initialValues); +} +</pre> + + <p>Call the <code>loadDictionary()</code> method wherever appropriate to populate the table. A + good place would be in the {@link android.database.sqlite.SQLiteOpenHelper#onCreate onCreate()} + method of the <code>DatabaseOpenHelper</code> class, right after you create the table:</p> + <pre> +@Override +public void onCreate(SQLiteDatabase db) { + mDatabase = db; + mDatabase.execSQL(FTS_TABLE_CREATE); + loadDictionary(); +} +</pre> + + <h2 id="search">Search for the Query</h2> + + <p>When you have the virtual table created and populated, use the query supplied by your {@link + android.widget.SearchView} to search the data. Add the following methods to the + <code>DatabaseTable</code> class to build a SQL statement that searches for the query:</p> + <pre> +public Cursor getWordMatches(String query, String[] columns) { + String selection = COL_WORD + " MATCH ?"; + String[] selectionArgs = new String[] {query+"*"}; + + return query(selection, selectionArgs, columns); +} + +private Cursor query(String selection, String[] selectionArgs, String[] columns) { + SQLiteQueryBuilder builder = new SQLiteQueryBuilder(); + builder.setTables(FTS_VIRTUAL_TABLE); + + Cursor cursor = builder.query(mDatabaseOpenHelper.getReadableDatabase(), + columns, selection, selectionArgs, null, null, null); + + if (cursor == null) { + return null; + } else if (!cursor.moveToFirst()) { + cursor.close(); + return null; + } + return cursor; +} +</pre> + + <p>Search for a query by calling <code>getWordMatches()</code>. Any matching results are returned + in a {@link android.database.Cursor} that you can iterate through or use to build a {@link android.widget.ListView}. + This example calls <code>getWordMatches()</code> in the <code>handleIntent()</code> method of the searchable + activity. Remember that the searchable activity receives the query inside of the {@link + android.content.Intent#ACTION_SEARCH} intent as an extra, because of the intent filter that you + previously created:</p> + <pre> +DatabaseTable db = new DatabaseTable(this); + +... + +private void handleIntent(Intent intent) { + + if (Intent.ACTION_SEARCH.equals(intent.getAction())) { + String query = intent.getStringExtra(SearchManager.QUERY); + Cursor c = db.getWordMatches(query, null); + //process Cursor and display results + } +} +</pre>
\ No newline at end of file diff --git a/docs/html/training/search/setup.jd b/docs/html/training/search/setup.jd new file mode 100644 index 0000000..044e422 --- /dev/null +++ b/docs/html/training/search/setup.jd @@ -0,0 +1,197 @@ +page.title=Setting Up the Search Interface +trainingnavtop=true +next.title=Storing and Searching for Data +next.link=search.html + +@jd:body + + <div id="tb-wrapper"> + <div id="tb"> + <h2>This lesson teaches you to</h2> + + <ul> + <li><a href="{@docRoot}training/search/setup.html#add-sv">Add the Search View to the Action + Bar</a></li> + + <li><a href="{@docRoot}training/search/setup.html#create-sc">Create a Searchable + Configuration</a></li> + + <li><a href="{@docRoot}training/search/setup.html#create-sa">Create a Searchable + Activity</a></li> + </ul> + + <h2>You should also read:</h2> + + <ul> + <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a></li> + </ul> + </div> + </div> + + <p>Beginning in Android 3.0, using the {@link android.widget.SearchView} widget as an item in + the action bar is the preferred way to provide search in your app. Like with all items in + the action bar, you can define the {@link android.widget.SearchView} to show at all times, only + when there is room, or as a collapsible action, which displays the {@link + android.widget.SearchView} as an icon initially, then takes up the entire action bar as a search + field when the user clicks the icon.</p> + + <p class="note"><strong>Note:</strong> Later in this class, you will learn how to make your + app compatible down to Android 2.1 (API level 7) for devices that do not support + {@link android.widget.SearchView}.</p> + + <h2 id="add-sv">Add the Search View to the Action Bar</h2> + + <p>To add a {@link android.widget.SearchView} widget to the action bar, create a file named + <code>res/menu/options_menu.xml</code> in your project and add the following code to the file. + This code defines how to create the search item, such as the icon to use and the title of the + item. The <code>collapseActionView</code> attribute allows your {@link android.widget.SearchView} + to expand to take up the whole action bar and collapse back down into a + normal action bar item when not in use. Because of the limited action bar space on handset devices, + using the <code>collapsibleActionView</code> attribute is recommended to provide a better + user experience.</p> + <pre> +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/search" + android:title="@string/search_title" + android:icon="@drawable/ic_search" + android:showAsAction="collapseActionView|ifRoom" + android:actionViewClass="android.widget.SearchView" /> +</menu> +</pre> + + <p class="note"><strong>Note:</strong> If you already have an existing XML file for your menu + items, you can add the <code><item></code> element to that file instead.</p> + + <p>To display the {@link android.widget.SearchView} in the action bar, inflate the XML menu + resource (<code>res/menu/options_menu.xml</code>) in the {@link + android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} method of your activity:</p> + <pre> +@Override +public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.options_menu, menu); + + return true; +} +</pre> + + <p>If you run your app now, the {@link android.widget.SearchView} appears in your app's action + bar, but it isn't functional. You now need to define <em>how</em> the {@link + android.widget.SearchView} behaves.</p> + + <h2 id="create-sc">Create a Searchable Configuration</h2> + + <p>A <a href="http://developer.android.com/guide/topics/search/searchable-config.html">searchable + configuration</a> defines how the {@link android.widget.SearchView} behaves and is defined in a + <code>res/xml/searchable.xml</code> file. At a minimum, a searchable configuration must contain + an <code>android:label</code> attribute that has the same value as the + <code>android:label</code> attribute of the <a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a> or + <a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a> element in your Android manifest. + However, we also recommend adding an <code>android:hint</code> attribute to give the user an idea of what to enter into the search + box:</p> + <pre> +<?xml version="1.0" encoding="utf-8"?> + +<searchable xmlns:android="http://schemas.android.com/apk/res/android" + android:label="@string/app_name" + android:hint="@string/search_hint" /> +</pre> + + <p>In your application's manifest file, declare a <a href="{@docRoot}guide/topics/manifest/meta-data-element.html"> + <code><meta-data></code></a> element that points to the <code>res/xml/searchable.xml</code> file, + so that your application knows where to find it. Declare the element in an <code><activity></code> + that you want to display the {@link android.widget.SearchView} in:</p> + <pre> +<activity ... > + ... + <meta-data android:name="android.app.searchable" + android:resource="@xml/searchable" /> + +</activity> +</pre> + + <p>In the {@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} method that you + created before, associate the searchable configuration with the {@link android.widget.SearchView} + by calling {@link android.widget.SearchView#setSearchableInfo}:</p> + <pre> +@Override +public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.options_menu, menu); + + // Associate searchable configuration with the SearchView + SearchManager searchManager = + (SearchManager) getSystemService(Context.SEARCH_SERVICE); + SearchView searchView = + (SearchView) menu.findItem(R.id.search).getActionView(); + searchView.setSearchableInfo( + searchManager.getSearchableInfo(getComponentName())); + + return true; +} +</pre> + + <p>The call to {@link android.app.SearchManager#getSearchableInfo getSearchableInfo()} obtains a + {@link android.app.SearchableInfo} object that is created from the searchable configuration XML + file. When the searchable configuration is correctly associated with your {@link + android.widget.SearchView}, the {@link android.widget.SearchView} starts an activity with the + {@link android.content.Intent#ACTION_SEARCH} intent when a user submits a query. You now need an + activity that can filter for this intent and handle the search query.</p> + + <h2 id="create-sa">Create a Searchable Activity</h2> + + <p>A {@link android.widget.SearchView} tries to start an activity with the {@link + android.content.Intent#ACTION_SEARCH} when a user submits a search query. A searchable activity + filters for the {@link android.content.Intent#ACTION_SEARCH} intent and searches for the query in + some sort of data set. To create a searchable activity, declare an activity of your choice to + filter for the {@link android.content.Intent#ACTION_SEARCH} intent:</p> + <pre> +<activity android:name=".SearchResultsActivity" ... > + ... + <intent-filter> + <action android:name="android.intent.action.SEARCH" /> + </intent-filter> + ... +</activity> +</pre> + + <p>In your searchable activity, handle the {@link android.content.Intent#ACTION_SEARCH} intent by + checking for it in your {@link android.app.Activity#onCreate onCreate()} method.</p> + + <p class="note"><strong>Note:</strong> If your searchable activity launches in single top mode + (<code>android:launchMode="singleTop"</code>), also handle the {@link + android.content.Intent#ACTION_SEARCH} intent in the {@link android.app.Activity#onNewIntent + onNewIntent()} method. In single top mode, only one instance of your activity is created and + subsequent calls to start your activity do not create a new activity on the + stack. This launch mode is useful so users can perform searches from the same activity + without creating a new activity instance every time.</p> + <pre> +public class SearchResultsActivity extends Activity { + + @Override + public void onCreate(Bundle savedInstanceState) { + ... + handleIntent(getIntent()); + } + + @Override + protected void onNewIntent(Intent intent) { + ... + handleIntent(intent); + } + + private void handleIntent(Intent intent) { + + if (Intent.ACTION_SEARCH.equals(intent.getAction())) { + String query = intent.getStringExtra(SearchManager.QUERY); + //use the query to search your data somehow + } + } + ... +} +</pre> + + <p>If you run your app now, the {@link android.widget.SearchView} can accept the user's query and + start your searchable activity with the {@link android.content.Intent#ACTION_SEARCH} intent. It + is now up to you to figure out how to store and search your data given a query.</p>
\ No newline at end of file |