progress towards impression and click stats on all sources, plus some internal cleanup

(framework portion)

suggestionCursor has new callbacks for impressions and clicks
- impressions now used to trigger "more" UI, cleanup apis around that

search dialog reports which position was clicked on via cursor#respond
- can now detect when sources under "more results" are clicked
- also used to simplify existing stuff:
  - can detect when "more results" entry is clicked and toggle base on that (no longer need INTENT_ACTION_CURSOR_RESPOND one off)
  - use response from click reporting to instruct which position should be selected
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 3675ec2..bcb2791 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -1174,7 +1174,7 @@
      */
     protected void launchQuerySearch(int actionKey, String actionMsg)  {
         String query = mSearchAutoComplete.getText().toString();
-        Intent intent = createIntent(Intent.ACTION_SEARCH, null, query, null, 
+        Intent intent = createIntent(Intent.ACTION_SEARCH, null, query, null,
                 actionKey, actionMsg);
         launchIntent(intent);
     }
@@ -1202,13 +1202,26 @@
     protected boolean launchSuggestion(int position, int actionKey, String actionMsg) {
         Cursor c = mSuggestionsAdapter.getCursor();
         if ((c != null) && c.moveToPosition(position)) {
+            // let the cursor know which position was clicked
+            final Bundle clickResponse = new Bundle(1);
+            clickResponse.putInt(SearchManager.RESPOND_EXTRA_POSITION_CLICKED, position);
+            final Bundle response = c.respond(clickResponse);
+
+            // the convention is to send a position to select in response to a click (if applicable)
+            final int posToSelect = response.getInt(
+                    SearchManager.RESPOND_EXTRA_POSITION_SELECTED,
+                    SuggestionsAdapter.NO_ITEM_TO_SELECT);
+            mSuggestionsAdapter.setListItemToSelect(posToSelect);            
+
+            // launch the intent
             Intent intent = createIntentFromSuggestion(c, actionKey, actionMsg);
             launchIntent(intent);
+
             return true;
         }
         return false;
     }
-    
+
     /**
      * Launches an intent. Also dismisses the search dialog if not in global search mode.
      */
@@ -1235,9 +1248,6 @@
         if (SearchManager.INTENT_ACTION_CHANGE_SEARCH_SOURCE.equals(action)) {
             handleChangeSourceIntent(intent);
             return true;
-        } else if (SearchManager.INTENT_ACTION_CURSOR_RESPOND.equals(action)) {
-            handleCursorRespondIntent(intent);
-            return true;
         }
         return false;
     }
@@ -1268,34 +1278,14 @@
         String query = intent.getStringExtra(SearchManager.QUERY);
         setUserQuery(query);
     }
-    
-    /**
-     * Handles {@link SearchManager#INTENT_ACTION_CURSOR_RESPOND}.
-     */
-    private void handleCursorRespondIntent(Intent intent) {
-        Cursor c = mSuggestionsAdapter.getCursor();
-        if (c != null) {
-            Bundle response = c.respond(intent.getExtras());
-            
-            // The SHOW_CORPUS_SELECTORS command to the cursor also returns a value in
-            // its bundle, keyed by the same command string, which contains the index
-            // of the "More results..." list item, which we use to instruct the
-            // AutoCompleteTextView's list to scroll to that item when the item is
-            // clicked.
-            if (response.containsKey(SuggestionsAdapter.SHOW_CORPUS_SELECTORS)) {
-                int indexOfMore = response.getInt(SuggestionsAdapter.SHOW_CORPUS_SELECTORS);
-                mSuggestionsAdapter.setListItemToSelect(indexOfMore);
-            }
-        }
-    }
-    
+
     /**
      * Sets the list item selection in the AutoCompleteTextView's ListView.
      */
     public void setListSelection(int index) {
         mSearchAutoComplete.setListSelection(index);
     }
-    
+
     /**
      * Saves the previous component that was searched, so that we can go
      * back to it.
@@ -1365,6 +1355,12 @@
         try {
             // use specific action if supplied, or default action if supplied, or fixed default
             String action = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_ACTION);
+
+            // some items are display only, or have effect via the cursor respond click reporting.
+            if (SearchManager.INTENT_ACTION_NONE.equals(action)) {
+                return null;
+            }
+
             if (action == null) {
                 action = mSearchable.getSuggestIntentAction();
             }
@@ -1387,7 +1383,7 @@
             Uri dataUri = (data == null) ? null : Uri.parse(data);
 
             String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
-            
+
             String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY);
 
             return createIntent(action, dataUri, query, extraData, actionKey, actionMsg);
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index be2f50f..b4a3a78 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1148,7 +1148,7 @@
      * @hide
      */
     public final static String SOURCE = "source";
-    
+
     /**
      * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
      * {@link android.content.Intent#getIntExtra content.Intent.getIntExtra()}
@@ -1162,10 +1162,44 @@
     /**
      * Intent extra data key: This key will be used for the extra populated by the
      * {@link #SUGGEST_COLUMN_INTENT_EXTRA_DATA} column.
+     *
      * {@hide}
      */
     public final static String EXTRA_DATA_KEY = "intent_extra_data_key";
-    
+
+
+    /**
+     * Used by the search dialog to ask the global search provider whether there are any pending
+     * sources that have yet to respond.  Specifically, the search dialog will call
+     * {@link Cursor#respond} with a bundle containing this extra as a key, and expect the same key
+     * to be in the response, with a boolean value indicating whether there are pending sources.
+     *
+     * {@hide}
+     */
+    public final static String RESPOND_EXTRA_PENDING_SOURCES = "respond_extra_pending_sources";
+
+    /**
+     * Used by the search dialog to tell the cursor that supplied suggestions which item was clicked
+     * before launching the intent.  The search dialog will call {@link Cursor#respond} with a
+     * bundle containing this extra as a key and the position that was clicked as the value.
+     *
+     * The response bundle will use {@link #RESPOND_EXTRA_POSITION_SELECTED} to return an int value
+     * of the index that should be selected, if applicable.
+     *
+     * {@hide}
+     */
+    public final static String RESPOND_EXTRA_POSITION_CLICKED = "respond_extra_position_clicked";
+
+    /**
+     * Used as a key in the response bundle from a call to {@link Cursor#respond} that sends the
+     * position that is clicked.
+     *
+     * @see #RESPOND_EXTRA_POSITION_CLICKED
+     *
+     * {@hide}
+     */
+    public final static String RESPOND_EXTRA_POSITION_SELECTED = "respond_extra_position_selected";
+
     /**
      * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
      * {@link android.content.Intent#getStringExtra content.Intent.getStringExtra()}
@@ -1304,7 +1338,7 @@
      *  to provide additional arbitrary data which will be included as an extra under the key
      *  {@link #EXTRA_DATA_KEY}. For use by the global search system only - if other providers
      *  attempt to use this column, the value will be overwritten by global search.
-     * 
+     *
      * @hide
      */
     public final static String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
@@ -1363,21 +1397,7 @@
      */
     public final static String INTENT_ACTION_CHANGE_SEARCH_SOURCE 
             = "android.search.action.CHANGE_SEARCH_SOURCE";
-    
-    /**
-     * If a suggestion has this value in {@link #SUGGEST_COLUMN_INTENT_ACTION},
-     * the search dialog will call {@link Cursor#respond(Bundle)} when the
-     * suggestion is clicked. 
-     * 
-     * The {@link Bundle} argument will be constructed
-     * in the same way as the "extra" bundle included in an Intent constructed 
-     * from the suggestion.
-     * 
-     * @hide Pending API council approval.
-     */
-    public final static String INTENT_ACTION_CURSOR_RESPOND
-            = "android.search.action.CURSOR_RESPOND";
-    
+
     /**
      * Intent action for finding the global search activity.
      * The global search provider should handle this intent.
@@ -1395,6 +1415,14 @@
      */
     public final static String INTENT_ACTION_SEARCH_SETTINGS 
             = "android.search.action.SEARCH_SETTINGS";
+
+    /**
+     * If a suggestion has this value in {@link #SUGGEST_COLUMN_INTENT_ACTION},
+     * the search dialog will take no action.
+     *
+     * @hide
+     */
+    public final static String INTENT_ACTION_NONE = "android.search.action.ZILCH";
     
     /**
      * Reference to the shared system search service.
@@ -1506,25 +1534,27 @@
     }
     
     /**
-     * See {@link #setOnDismissListener} for configuring your activity to monitor search UI state.
+     * See {@link SearchManager#setOnDismissListener} for configuring your activity to monitor
+     * search UI state.
      */
     public interface OnDismissListener {
         /**
-         * This method will be called when the search UI is dismissed. To make use if it, you must
-         * implement this method in your activity, and call {@link #setOnDismissListener} to 
-         * register it.
+         * This method will be called when the search UI is dismissed. To make use of it, you must
+         * implement this method in your activity, and call
+         * {@link SearchManager#setOnDismissListener} to register it.
          */
         public void onDismiss();
     }
     
     /**
-     * See {@link #setOnCancelListener} for configuring your activity to monitor search UI state.
+     * See {@link SearchManager#setOnCancelListener} for configuring your activity to monitor
+     * search UI state.
      */
     public interface OnCancelListener {
         /**
          * This method will be called when the search UI is canceled. To make use if it, you must
-         * implement this method in your activity, and call {@link #setOnCancelListener} to 
-         * register it.
+         * implement this method in your activity, and call
+         * {@link SearchManager#setOnCancelListener} to register it.
          */
         public void onCancel();
     }
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 33c4769..451697a 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -72,14 +72,16 @@
     private int mIconName2Col;
     private int mIconBitmap1Col;
     private int mIconBitmap2Col;
-    
+
     // This value is stored in SuggestionsAdapter by the SearchDialog to indicate whether
     // a particular list item should be selected upon the next call to notifyDataSetChanged.
     // This is used to indicate the index of the "More results..." list item so that when
     // the data set changes after a click of "More results...", we can correctly tell the
-    // ListView to scroll to the right line item. It gets reset to -1 every time it is consumed.
-    private int mListItemToSelect = -1;
-    
+    // ListView to scroll to the right line item. It gets reset to NO_ITEM_TO_SELECT every time it
+    // is consumed.
+    private int mListItemToSelect = NO_ITEM_TO_SELECT;
+    static final int NO_ITEM_TO_SELECT = -1;
+
     public SuggestionsAdapter(Context context, SearchDialog searchDialog, SearchableInfo searchable,
             WeakHashMap<String, Drawable> outsideDrawablesCache, boolean globalSearchMode) {
         super(context,
@@ -146,9 +148,9 @@
     public void notifyDataSetChanged() {
         super.notifyDataSetChanged();
         updateWorking();
-        if (mListItemToSelect != -1) {
+        if (mListItemToSelect != NO_ITEM_TO_SELECT) {
             mSearchDialog.setListSelection(mListItemToSelect);
-            mListItemToSelect = -1;
+            mListItemToSelect = NO_ITEM_TO_SELECT;
         }
     }
     
@@ -168,14 +170,12 @@
         if (!mGlobalSearchMode || mCursor == null) return;
         
         Bundle request = new Bundle();
-        request.putString(SearchManager.EXTRA_DATA_KEY, IS_WORKING);
+        request.putString(SearchManager.RESPOND_EXTRA_PENDING_SOURCES, "DUMMY");
         Bundle response = mCursor.respond(request);
-        if (response.containsKey(IS_WORKING)) {
-            boolean isWorking = response.getBoolean(IS_WORKING);
-            mSearchDialog.setWorking(isWorking);
-        }
+
+        mSearchDialog.setWorking(response.getBoolean(SearchManager.RESPOND_EXTRA_PENDING_SOURCES));
     }
-    
+
     /**
      * Tags the view with cached child view look-ups.
      */
@@ -408,7 +408,7 @@
      */
     public static String getColumnString(Cursor cursor, String columnName) {
         int col = cursor.getColumnIndex(columnName);
-        if (col == -1) {
+        if (col == NO_ITEM_TO_SELECT) {
             return null;
         }
         return cursor.getString(col);