Ch14 Listings

satya - Friday, February 26, 2010 10:47:40 AM

Listing 14-1. Regular Activity Source Code


//filename: RegularActivity.java
public class RegularActivity extends Activity
{
   private final String tag = "RegularActivity";
   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
   }
   @Override
   public boolean onCreateOptionsMenu(Menu menu)
   {
      //call the parent to attach any system level menus
      super.onCreateOptionsMenu(menu);
      MenuInflater inflater = getMenuInflater(); //from activity
      inflater.inflate(R.menu.main_menu, menu);
      return true;
   }
   @Override
   public boolean onOptionsItemSelected(MenuItem item)
   {
      appendMenuItemText(item);
      if (item.getItemId() == R.id.menu_clear) {
         this.emptyText();
         return true;
      }
      if (item.getItemId() == R.id.mid_no_search) {
         this.invokeNoSearchActivity();
         return true;
      }
      if (item.getItemId() == R.id.mid_local_search) {
         this.invokeLocalSearchActivity();
         return true;
      }
      if (item.getItemId() == R.id.mid_invoke_search) {
         this.invokeSearchInvokerActivity();
         return true;
      }
      return true;
   }
   private TextView getTextView()
   {
      return (TextView)this.findViewById(R.id.text1);
   }
   private void appendMenuItemText(MenuItem menuItem)
   {
      String title = menuItem.getTitle().toString();
      TextView tv = getTextView();
      tv.setText(tv.getText() + "\n" + title);
   }
   private void emptyText()
   {
      TextView tv = getTextView();
      tv.setText("");
   }
   private void invokeNoSearchActivity()
   {
      Intent intent = new Intent(this,NoSearchActivity.class);
      startActivity(intent);
   }
   private void invokeSearchInvokerActivity()
   {
      Intent intent = new Intent(this,SearchInvokerActivity.class);
      startActivity(intent);
   }
   private void invokeLocalSearchActivity()
   {
      Intent intent = new Intent(this,LocalSearchEnabledActivity.class);
      startActivity(intent);
   }
}

satya - Friday, February 26, 2010 10:53:14 AM

Listing 14-2. Activity/Search Key Interaction: Manifest File


//filename: manifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ai.android.search.nosearch">
<application android:icon="@drawable/icon"
   android:label="Test Activity QSB Interaction">
   <activity android:name=".RegularActivity"
      android:label="Activity/QSB Interaction:Regular Activity">
      <intent-filter>
         <action android:name="android.intent.action.MAIN" />
         <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
   </activity>

   <activity android:name=".NoSearchActivity"
      android:label="Activity/QSB Interaction::Disabled Search">
   </activity>

   <activity android:name=".SearchInvokerActivity"
      android:label="Activity/QSB Interaction::Search Invoker">
   </activity>

   <activity android:name=".LocalSearchEnabledActivity"
      android:label="Activity/QSB Interaction::Local Search">
      <meta-data android:name="android.app.default_searchable"
         android:value=".SearchActivity" />
   </activity>

   <activity android:name=".SearchActivity"
      android:label="Activity/QSB Interaction::Search Results">
      <intent-filter>
         <action android:name="android.intent.action.SEARCH" />
         <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
      <meta-data android:name="android.app.searchable"
         android:resource="@xml/searchable" />
   </activity>
<!--
<meta-data android:name="android.app.default_searchable"
android:value="*" />
-->
</application>
<uses-sdk android:minSdkVersion="4" />
</manifest>

satya - Friday, February 26, 2010 10:55:30 AM

Listing 14-3. Regular Activity Layout File


//filename: layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >
   <TextView
      android:id="@+id/text1"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="@string/regular_activity_prompt"
   />
</LinearLayout>

satya - Friday, February 26, 2010 10:55:56 AM

Listing 14-4. Activity/Search Key Interaction: strings.xml


//filename: /res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
	<!--
	CHAPTER 14: Android Search 507
	**************************************************
	* regular_activity_prompt
	**************************************************
	-->
	<string name="regular_activity_prompt">
This is a sample application to test how QSB and Search Key
interacts with activities. This application has 4 activities
including this one. The activity you are looking at is
called a Regular Activity and is one of 4. The other three
you can access through the menu.
\n\n
This activity is a regular activity that is unaware of
any search capabilities. If you click search key now
it will invoke the global search.
\n
\nThe other activities demonstrate:`
\n\n1) No search Activity: An activity that disables search
\n2) Invoke search: programatically invoke global search
\n3) Local Search Activity: Invoke Local Search
\n
\nYour debug will appear here
	</string>
	<!--
	**************************************************
	* no_search_activity_prompt
	**************************************************
	-->
	<string name="no_search_activity_prompt">
In this activity the onSearchRequested
returns a false. The search button
should be ignored now.
\n
\nYou can click back now to access the
previous activity and use the menus again
to choose other activities.
	</string>
	<!--
	**************************************************
	* search_activity_prompt
	**************************************************
	-->
	<string name="search_activity_prompt">
This is called a search activity or search results activity. This activity
is invoked by clicking on the search key when
some other activity uses this activity as its
search results activity.
\n\n
Typically you can retrieve the query string
from the intent to see what the query is.
	</string>
	<!--
	**************************************************
	* search_invoker_activity_prompt
	**************************************************
	-->
	<string name="search_invoker_activity_prompt">
In this activity a search menu item is used
to invoke the default search. In this case
as there is no local search for this activity
specified global search is invoked. Use the
menu button to see the "search" menu. when you
click on that search menu you will see the
global search.
	</string>
	<!--
	**************************************************
	* local_search_enabled_activity_prompt
	**************************************************
	-->
	<string name="local_search_enabled_activity_prompt">
This is a very simple activity that has indicated through
the manifest file that there is a an associated search
activity. With this association when the search key is
pressed the local search is presented instead of global.
\n\n
You can see the local nature of it by looking at the
label of the QSB and also the hint in the QSB. Both
came from the search metadata.
\n\n
Once you click on the query icon, it will transfer
you to the local search activity.
	</string>
	<!--
	**************************************************
	* Other values
	**************************************************
	<string name="app_name">Sample Search Application</string>
	-->
	<string name="search_label">Local Search Demo</string>
	<string name="search_hint">Local Search Demo Hint</string>
</resources>

satya - Friday, February 26, 2010 10:59:34 AM

Listing 14-5. Regular Activity Menu File


//filename: /res/menu/main_menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
   <!-- This group uses the default category. -->
   <group android:id="@+id/menuGroup_Main">
      <item android:id="@+id/mid_no_search"
         android:title="No Search Activity" />
      <item android:id="@+id/mid_local_search"
         android:title="Local Search Activity" />
      <item android:id="@+id/mid_invoke_search"
         android:title="Search Invoker Activity" />
      <item android:id="@+id/menu_clear"
         android:title="clear" />
   </group>
</menu>

satya - Friday, February 26, 2010 10:59:52 AM

Listing 14-6. Activity Disabling Search


//filename: NoSearchActivity.java
public class NoSearchActivity extends Activity
{
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.no_search_activity);
      return;
   }
   @Override
   public boolean onSearchRequested()
   {
      return false;
   }
}

satya - Friday, February 26, 2010 11:00:10 AM

Listing 14-7. NoSearchActivity XML File


//filename: layout/no_search_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >
   <TextView
      android:id="@+id/text1"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="@string/no_search_activity_prompt"
   />
</LinearLayout>

satya - Friday, February 26, 2010 11:00:29 AM

Listing 14-8. SearchInvokerActivity


//filename: SearchInvokerActivity.java
public class SearchInvokerActivity extends Activity
{
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.search_invoker_activity);
	}
	@Override
	public boolean onCreateOptionsMenu(Menu menu)
	{
		super.onCreateOptionsMenu(menu);
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.search_invoker_menu, menu);
		return true;
	}
	@Override
	public boolean onOptionsItemSelected(MenuItem item)
	{
		appendMenuItemText(item);
		if (item.getItemId() == R.id.mid_si_clear)
		{
			this.emptyText();
			return true;
		}
		if (item.getItemId() == R.id.mid_si_search)
		{
			this.invokeSearch();
			return true;
		}
		return true;
	}
	private TextView getTextView()
	{
		return (TextView)this.findViewById(R.id.text1);
	}
	private void appendMenuItemText(MenuItem menuItem)
	{
		String title = menuItem.getTitle().toString();
		TextView tv = getTextView();
		tv.setText(tv.getText() + "\n" + title);
	}
	private void emptyText()
	{
		TextView tv = getTextView();
		tv.setText("");
	}
	private void invokeSearch()
	{
		this.onSearchRequested();
	}
}

satya - Friday, February 26, 2010 11:00:48 AM

Listing 14-9. SearchInvokerActivity XML


//filename: layout/search_invoker_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >
   <TextView
      android:id="@+id/text1"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="@string/search_invoker_activity_prompt"
   />
</LinearLayout>

satya - Friday, February 26, 2010 11:01:05 AM

Listing 14-10. SearchInvokerActivity Menu XML


//filename:menu/search_invoker_menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
   <!-- This group uses the default category. -->
   <group android:id="@+id/menuGroup_Main">
      <item android:id="@+id/mid_si_search"
         android:title="Search" />
      <item android:id="@+id/mid_si_clear"
         android:title="clear" />
   </group>
</menu>

satya - Friday, February 26, 2010 11:01:23 AM

Listing 14-11. SearchActivity


//filename: SearchActivity.java
public class SearchActivity extends Activity
{
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.search_activity);
      return;
   }
}

satya - Friday, February 26, 2010 11:03:04 AM

Listing 14-12. Searchable.xml: Search Metadata


///res/xml/searchable.xml
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
   android:label="@string/search_label"
   android:hint="@string/search_hint"
   android:searchMode="showSearchLabelAsBadge"
/>

satya - Friday, February 26, 2010 11:03:24 AM

Listing 14-13. LocalSearchEnabledActivity


//filename: LocalSearchEnabledActivity.java
public class LocalSearchEnabledActivity extends Activity
{
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.local_search_enabled_activity);
      return;
   }
}

satya - Friday, February 26, 2010 11:03:42 AM

Listing 14-14. LocalSearchEnabledActivity Layout File


//filename:local_search_enabled_activity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >
   <TextView
      android:id="@+id/text1"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="@string/local_search_enabled_activity_prompt"
   />
</LinearLayout>

satya - Friday, February 26, 2010 11:04:02 AM

Listing 14-15. SimpleSuggestionProvider.java


//SimpleSuggestionProvider.java
public class SimpleSuggestionProvider
extends SearchRecentSuggestionsProvider {
   final static String AUTHORITY =
         "com.ai.android.search.simplesp.SimpleSuggestionProvider";
   final static int MODE = DATABASE_MODE_QUERIES;

   public SimpleSuggestionProvider() {
      super();
      setupSuggestions(AUTHORITY, MODE);
   }
}

satya - Friday, February 26, 2010 11:04:27 AM

Listing 14-16. SimpleSuggestionProvider Manifest File


//filename: manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.ai.android.search.simplesp"
      android:versionCode="1"
      android:versionName="1.0.0">
   <application android:icon="@drawable/icon"
         android:label="Simple Search Suggestion Provider:SSSP">
      <activity android:name=".SimpleMainActivity"
            android:label="SSSP:Simple Main Activity">
         <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
         </intent-filter>
      </activity>
      <!--
      ****************************************************************
      * Search related code: search activity
      ****************************************************************
      -->
      <activity android:name=".SearchActivity"
            android:label="SSSP: Search Activity"
            android:launchMode="singleTop">
         <intent-filter>
            <action android:name="android.intent.action.SEARCH" />
            <category android:name="android.intent.category.DEFAULT" />
         </intent-filter>
         <meta-data android:name="android.app.searchable"
            android:resource="@xml/searchable" />
      </activity>

      <meta-data android:name="android.app.default_searchable"
         android:value=".SearchActivity" />
      <provider android:name=".SimpleSuggestionProvider"
            android:authorities
            ="com.ai.android.search.simplesp.SimpleSuggestionProvider" />
   </application>
<uses-sdk android:minSdkVersion="4" />
</manifest>

satya - Friday, February 26, 2010 11:04:49 AM

Listing 14-17. SimpleSuggestionProvider Search Activity


//filename: SearchActivity.java
public class SearchActivity extends Activity
{
   private final static String tag ="SearchActivity";

   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      Log.d(tag,"I am being created");

      //otherwise do this
      setContentView(R.layout.layout_test_search_activity);

      //this.setDefaultKeyMode(Activity.DEFAULT_KEYS_SEARCH_GLOBAL);
      this.setDefaultKeyMode(Activity.DEFAULT_KEYS_SEARCH_LOCAL);

      // get and process search query here
      final Intent queryIntent = getIntent();
      final String queryAction = queryIntent.getAction();

      if (Intent.ACTION_SEARCH.equals(queryAction))
      {
         Log.d(tag,"new intent for search");
         this.doSearchQuery(queryIntent);
      }
      else {
         Log.d(tag,"new intent NOT for search");
      }
      return;
   }

   @Override
   public void onNewIntent(final Intent newIntent)
   {
      super.onNewIntent(newIntent);
      Log.d(tag,"new intent calling me");

      // get and process search query here
      final Intent queryIntent = getIntent();
      final String queryAction = queryIntent.getAction();
      if (Intent.ACTION_SEARCH.equals(queryAction))
      {
         this.doSearchQuery(queryIntent);
         Log.d(tag,"new intent for search");
      }
      else {
         Log.d(tag,"new intent NOT for search");
      }
   }
   private void doSearchQuery(final Intent queryIntent)
   {
      final String queryString =
         queryIntent.getStringExtra(SearchManager.QUERY);
   
      // Record the query string in the recent queries suggestions provider.
      SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
      SimpleSuggestionProvider.AUTHORITY,
      SimpleSuggestionProvider.MODE);
      suggestions.saveRecentQuery(queryString, null);
   }
}

satya - Friday, February 26, 2010 11:05:12 AM

Listing 14-18. SimpleSuggestionProvider Search Metadata


//filename: searchable.xml
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
   android:label="@string/search_label"
   android:hint="@string/search_hint"
   android:searchMode="showSearchLabelAsBadge"
   android:includeInGlobalSearch="true"
   android:searchSuggestAuthority=
      "com.ai.android.search.simplesp.SimpleSuggestionProvider"
   android:searchSuggestSelection=" ? "
/>

satya - Friday, February 26, 2010 11:05:32 AM

Listing 14-19. SimpleSuggestionProvider: Main Activity


public class SimpleMainActivity extends Activity
{
   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
   }
}

satya - Friday, February 26, 2010 11:05:54 AM

Listing 14-20. CustomSuggestionProvider Source Code


public class SuggestUrlProvider extends ContentProvider
{
   private static final String tag = "SuggestUrlProvider";
   public static String AUTHORITY =
         "com.ai.android.search.custom.suggesturlprovider";
   private static final int SEARCH_SUGGEST = 0;
   private static final int SHORTCUT_REFRESH = 1;
   private static final UriMatcher sURIMatcher = buildUriMatcher();

   private static final String[] COLUMNS = {
      "_id", // must include this column
      SearchManager.SUGGEST_COLUMN_TEXT_1,
      538 CHAPTER 14: Android Search
      SearchManager.SUGGEST_COLUMN_TEXT_2,
      SearchManager.SUGGEST_COLUMN_INTENT_DATA,
      SearchManager.SUGGEST_COLUMN_INTENT_ACTION,
      SearchManager.SUGGEST_COLUMN_SHORTCUT_ID
   };

   private static UriMatcher buildUriMatcher()
      {
      UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
      matcher.addURI(AUTHORITY,
                  SearchManager.SUGGEST_URI_PATH_QUERY,
                  SEARCH_SUGGEST);
      matcher.addURI(AUTHORITY,
                  SearchManager.SUGGEST_URI_PATH_QUERY +
                  "/*",
                  SEARCH_SUGGEST);
      matcher.addURI(AUTHORITY,
                        SearchManager.SUGGEST_URI_PATH_SHORTCUT,
                        SHORTCUT_REFRESH);
      matcher.addURI(AUTHORITY,
                  SearchManager.SUGGEST_URI_PATH_SHORTCUT +
                  "/*",
                  SHORTCUT_REFRESH);
      return matcher;
   }
   @Override
   public boolean onCreate() {
      //lets not do anything in particular
      Log.d(tag,"onCreate called");
      return true;
   }

   @Override
   public Cursor query(Uri uri, String[] projection, String selection,
   String[] selectionArgs, String sortOrder)
   {
      Log.d(tag,"query called with uri:" + uri);
      Log.d(tag,"selection:" + selection);
      String query = selectionArgs[0];
      Log.d(tag,"query:" + query);
      switch (sURIMatcher.match(uri)) {
         case SEARCH_SUGGEST:
            Log.d(tag,"search suggest called");
            return getSuggestions(query);

         case SHORTCUT_REFRESH:
            Log.d(tag,"shortcut refresh called");
            return null;

         default:
            throw new IllegalArgumentException("Unknown URL " + uri);
      }
   }

   private Cursor getSuggestions(String query)
   {
      if (query == null) return null;
      String word = getWord(query);

      if (word == null)
         return null;

      Log.d(tag,"query is longer than 3 letters");
      MatrixCursor cursor = new MatrixCursor(COLUMNS);

      //cursor.addRow(createRow(query,"row1"));
      cursor.addRow(createRow1(word));
      cursor.addRow(createRow2(word));
      return cursor;
   }

   private Object[] createRow1(String query)
   {
      return columnValuesOfQuery(query,
                     "android.intent.action.VIEW",
                     "http://www.thefreedictionary.com/" + query,
                     "Look up in freedictionary.com for",
                     query);
   }

   private Object[] createRow2(String query)
   {
      return columnValuesOfQuery(query,
                  "android.intent.action.VIEW",
                  "http://www.google.com/search?hl=en&source=hp&q=define%3A/"
                  + query,
                  "Look up in google.com for",
                  query);
   }
   private Object[] columnValuesOfQuery(String query,
                                 String intentAction,
                                 String url,
                                 String text1,
                                 String text2)
   {
      return new String[] {
                  query, // _id
                  text1, // text1
                  text2, // text2
                  url, // intent_data (included when clicking on item)
                  intentAction, //action
                  SearchManager.SUGGEST_NEVER_MAKE_SHORTCUT
      };
   }
   private Cursor refreshShortcut(String shortcutId, String[] projection) {
      return null;
   }
   public String getType(Uri uri) {
      switch (sURIMatcher.match(uri)) {
         case SEARCH_SUGGEST:
            return SearchManager.SUGGEST_MIME_TYPE;
         case SHORTCUT_REFRESH:
            return SearchManager.SHORTCUT_MIME_TYPE;
         default:
         throw new IllegalArgumentException("Unknown URL " + uri);
      }
   }

   public Uri insert(Uri uri, ContentValues values) {
      throw new UnsupportedOperationException();
   }

   public int delete(Uri uri, String selection, String[] selectionArgs) {
      throw new UnsupportedOperationException();
   }

   public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
         throw new UnsupportedOperationException();
   }

   private String getWord(String query)
   {
      int dotIndex = query.indexOf('.');
      if (dotIndex < 0)
         return null;
      return query.substring(0,dotIndex);
   }
}

satya - Friday, February 26, 2010 11:06:26 AM

Listing 14-21. CustomSuggestionProvider Search Metadata


//xml/searchable.xml
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
	android:label="@string/search_label"
	android:hint="@string/search_hint"
	android:searchMode="showSearchLabelAsBadge"
	android:searchSettingsDescription="suggests urls"
	android:includeInGlobalSearch="true"
	android:searchSuggestAuthority="com.ai.android.search.custom.suggesturlprovider"
	android:searchSuggestIntentAction="android.intent.action.VIEW"
	android:searchSuggestSelection=" ? "
/>

satya - Friday, February 26, 2010 11:06:49 AM

Listing 14-22. Defining Suggestion Cursor Columns


private static final String[] COLUMNS = {
   "_id", // must include this column
   SearchManager.SUGGEST_COLUMN_TEXT_1,
   SearchManager.SUGGEST_COLUMN_TEXT_2,
   SearchManager.SUGGEST_COLUMN_INTENT_DATA,
   SearchManager.SUGGEST_COLUMN_INTENT_ACTION,
   SearchManager.SUGGEST_COLUMN_SHORTCUT_ID
};

satya - Friday, February 26, 2010 11:07:13 AM

Listing 14-23. SearchActivity


//file: SearchActivity.java
public class SearchActivity extends Activity
{
   private final static String tag ="SearchActivity";

   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      Log.d(tag,"I am being created");
      setContentView(R.layout.layout_test_search_activity);

      // get and process search query here
      final Intent queryIntent = getIntent();

      //query action
      final String queryAction = queryIntent.getAction();
      Log.d(tag,"Create Intent action:"+queryAction);

      final String queryString =
         queryIntent.getStringExtra(SearchManager.QUERY);
      Log.d(tag,"Create Intent query:"+queryString);

      if (Intent.ACTION_SEARCH.equals(queryAction))
      {
         this.doSearchQuery(queryIntent);
      }
      else if (Intent.ACTION_VIEW.equals(queryAction))
      {
         this.doView(queryIntent);
      }
      else {
         Log.d(tag,"Create intent NOT from search");
      }
      return;
   }

   @Override
   public void onNewIntent(final Intent newIntent)
   {
      super.onNewIntent(newIntent);
      Log.d(tag,"new intent calling me");

      // get and process search query here
      final Intent queryIntent = newIntent;

      //query action
      final String queryAction = queryIntent.getAction();
      Log.d(tag,"New Intent action:"+queryAction);

      final String queryString =
         queryIntent.getStringExtra(SearchManager.QUERY);
      Log.d(tag,"New Intent query:"+queryString);
      if (Intent.ACTION_SEARCH.equals(queryAction))
      {
         this.doSearchQuery(queryIntent);
      }
      else if (Intent.ACTION_VIEW.equals(queryAction))
      {
         this.doView(queryIntent);
      }
      else {
         Log.d(tag,"New intent NOT from search");
      }
      return;
   }

   private void doSearchQuery(final Intent queryIntent)
   {
      final String queryString =
         queryIntent.getStringExtra(SearchManager.QUERY);
      appendText("You are searching for:" + queryString);
   }

   private void appendText(String msg)
   {
      TextView tv = (TextView)this.findViewById(R.id.text1);
      tv.setText(tv.getText() + "\n" + msg);
   }
   private void doView(final Intent queryIntent)
   {
      Uri uri = queryIntent.getData();
      String action = queryIntent.getAction();
      Intent i = new Intent(action);
      i.setData(uri);
      startActivity(i);
      this.finish();
   }
}

satya - Friday, February 26, 2010 11:07:34 AM

Listing 14-24. SearchActivity Layout XML


//file: layout_search_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >
   <TextView
      android:id="@+id/text1"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="@string/search_activity_main_text"
/>

satya - Friday, February 26, 2010 11:07:55 AM

Listing 14-25. strings.xml


<?xml version="1.0" encoding="utf-8"?>
<resources>
	<string name="search_activity_main_text">
This is the search activity.
\n\n
This will be invoked if action_search
is used as opposed to action_view.
\n\n
action_search happens if you press the search icon.
\n\n
action_view happens if you press on the suggestion
	</string>
	<string name="app_name">Custom Suggest Application</string>
	<string name="search_label">Custom Suggest Demo</string>
	<string name="search_hint">Custom Suggest Demo Hint</string>
</resources>

satya - Friday, February 26, 2010 11:08:15 AM

Listing 14-26. Finishing the Search Activity


private void doView(final Intent queryIntent)
{
   Uri uri = queryIntent.getData();
   String action = queryIntent.getAction();
   Intent i = new Intent(action);
   i.setData(uri);
   startActivity(i);
   this.finish();
}

satya - Friday, February 26, 2010 11:08:39 AM

Listing 14-27. Custom Suggestion Provider Manifest File


//file:manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ai.android.search.custom"
android:versionCode="1"
android:versionName="1.0.0">
   <application android:icon="@drawable/icon"
   android:label="Custom Suggestions Provider">
   <!--
   ****************************************************************
   * Search related code: search activity
   ****************************************************************
   -->
   <activity android:name=".SearchActivity"
   android:label="Search Activity Label"
   android:launchMode="singleTop">
      <intent-filter>
      <action android:name="android.intent.action.SEARCH" />
      <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
      <meta-data android:name="android.app.searchable"
         android:resource="@xml/searchable" />
   </activity>
      
   <!-- Declare default search -->
   <meta-data android:name="android.app.default_searchable"
      android:value=".SearchActivity" />

   <!-- Declare Suggestion Provider -->
   <provider android:name="SuggestUrlProvider"
      android:authorities="com.ai.android.search.custom.suggesturlprovider"
   />
   </application>
<uses-sdk android:minSdkVersion="4" />
</manifest>

satya - Friday, February 26, 2010 11:09:06 AM

Listing 14-28. List of Action Key Codes


keycode_dpad_up
keycode_dpad_down
keycode_dpad_left
keycode_dpad_right
keycode_dpad_center
keycode_back
keycode_call
keycode_camera
keycode_clear
kecode_endcall
keycode_home
keycode_menu
keycode_mute
keycode_power
keycode_search
keycode_volume_up
keycode_volume_down

satya - Friday, February 26, 2010 11:09:22 AM

Listing 14-29. Action Key Definition Example


<searchable xmlns:android="http://schemas.android.com/apk/res/android"
   android:label="@string/search_label"
   android:hint="@string/search_hint"
   android:searchMode="showSearchLabelAsBadge"
   android:includeInGlobalSearch="true"
   android:searchSuggestAuthority="com.ai.android.search.simplesp.SimpleSuggestionProvider"
   android:searchSuggestSelection=" ? "
>
<actionkey
   android:keycode="KEYCODE_CALL"
   android:queryActionMsg="call"
   android:suggestActionMsg="call"
   android:suggestActionMsgColumn="call_column" />

<actionkey
   android:keycode="KEYCODE_DPAD_CENTER"
   android:queryActionMsg="doquery"
   android:suggestActionMsg="dosuggest"
   android:suggestActionMsgColumn="my_column" />
.....
</searchable>

satya - Friday, February 26, 2010 11:10:39 AM

Listing 14-30. Example of Action Key Columns in the Suggestion Cursor


private static final String[] COLUMNS = {
   "_id", // must include this column
   SearchManager.SUGGEST_COLUMN_TEXT_1,
   SearchManager.SUGGEST_COLUMN_TEXT_2,
   SearchManager.SUGGEST_COLUMN_INTENT_DATA,
   SearchManager.SUGGEST_COLUMN_INTENT_ACTION,
   SearchManager.SUGGEST_COLUMN_SHORTCUT_ID,
   "call_column",
   "my_column"
};

satya - Friday, February 26, 2010 11:10:56 AM

Listing 14-31. Passing Additional Context


public boolean onSearchRequested()
{
   Bundle applicationData = new Bundle();
   applicationData.putString("string_key","some string value");
   applicationData.putLong("long_key",290904);
   applicationData.putFloat("float_key",2.0f);
   startSearch(null, // Initial Search search query string
            false, //don't "select initial query"
            applicationData, // extra data
            false // don't force a global search
            );
   return true;
}

satya - Friday, February 26, 2010 11:11:12 AM

Listing 14-32. Retrieving Additional Context


Bundle applicationData =
   queryIntent.getBundleExtra(SearchManager.APP_DATA);
   
if (applicationData != null)
{
   String s = applicationData.getString("string_key");
   long l = applicationData.getLong("long_key");
   float f = applicationData.getFloat("float_key");
}