Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1c54cf09 authored by Karl Rosaen's avatar Karl Rosaen
Browse files

Detect impressions, and cleanup the SearchDialog / SuggestionCursor communication.

(framework portion)

There are now 4 times the search dialog will check with the cursor:
- after data set changed
- when an item is clicked
- when the cursor is about to be closed
- when an item at a particular position is detected as showing

these are now the points where we can add data in either direction, which we use to accomplish:
- finding out whether there are any pending results
- find out if there is a position at which to notify when it is displayed (the "more results" triggering)
- toggling the "more results" button
- sending the max position that was displayed when the cursor is done

the new behavior (in addition to the refactoring) is improved detection of "more results" to trigger the additional sources
(it is now precise), and detection of which items were displayed to the user.
parent 241b4c74
Loading
Loading
Loading
Loading
+1 −10
Original line number Diff line number Diff line
@@ -1202,16 +1202,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
    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);            
            mSuggestionsAdapter.callCursorOnClick(c, position);

            // launch the intent
            Intent intent = createIntentFromSuggestion(c, actionKey, actionMsg);
+39 −27
Original line number Diff line number Diff line
@@ -1167,38 +1167,50 @@ public class SearchManager
     */
    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.
     * Defines the constants used in the communication between {@link android.app.SearchDialog} and
     * the global search provider via {@link Cursor#respond(android.os.Bundle)}.
     *
     * {@hide}
     * @hide
     */
    public final static String RESPOND_EXTRA_PENDING_SOURCES = "respond_extra_pending_sources";
    public static class DialogCursorProtocol {

        /**
     * 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}
         * The sent bundle will contain this integer key, with a value set to one of the events
         * below.
         */
    public final static String RESPOND_EXTRA_POSITION_CLICKED = "respond_extra_position_clicked";
        public final static String METHOD = "DialogCursorProtocol.method";

        /**
     * 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}
         * After data has been refreshed.
         */
    public final static String RESPOND_EXTRA_POSITION_SELECTED = "respond_extra_position_selected";
        public final static int POST_REFRESH = 0;
        public final static String POST_REFRESH_RECEIVE_ISPENDING
                = "DialogCursorProtocol.POST_REFRESH.isPending";
        public final static String POST_REFRESH_RECEIVE_DISPLAY_NOTIFY
                = "DialogCursorProtocol.POST_REFRESH.displayNotify";

        /**
         * Just before closing the cursor.
         */
        public final static int PRE_CLOSE = 1;
        public final static String PRE_CLOSE_SEND_MAX_DISPLAY_POS
                = "DialogCursorProtocol.PRE_CLOSE.sendDisplayPosition";

        /**
         * When a position has been clicked.
         */
        public final static int CLICK = 2;
        public final static String CLICK_SEND_POSITION
                = "DialogCursorProtocol.CLICK.sendPosition";
        public final static String CLICK_RECEIVE_SELECTED_POS
                = "DialogCursorProtocol.CLICK.receiveSelectedPosition";

        /**
         * When the threshold received in {@link #POST_REFRESH_RECEIVE_DISPLAY_NOTIFY} is displayed.
         */
        public final static int THRESH_HIT = 3;
    }

    /**
     * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
+85 −39
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ import android.widget.ImageView;
import android.widget.ResourceCursorAdapter;
import android.widget.TextView;

import static android.app.SearchManager.DialogCursorProtocol;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@@ -44,14 +46,6 @@ import java.util.WeakHashMap;
 * @hide
 */
class SuggestionsAdapter extends ResourceCursorAdapter {
    // The value used to query a cursor whether it is still expecting more input,
    // so we can correctly display (or not display) the 'working' spinner in the search dialog.
    public static final String IS_WORKING = "isWorking";
    
    // The value used to tell a cursor to display the corpus selectors, if this is global
    // search. Also returns the index of the more results item to allow the SearchDialog
    // to tell the ListView to scroll to that list item.
    public static final String SHOW_CORPUS_SELECTORS = "showCorpusSelectors";

    private static final boolean DBG = false;
    private static final String LOG_TAG = "SuggestionsAdapter";
@@ -73,10 +67,16 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
    // 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 NO_ITEM_TO_SELECT every time it
    // ListView to scroll to the right line item. It gets reset to NONE every time it
    // is consumed.
    private int mListItemToSelect = NO_ITEM_TO_SELECT;
    static final int NO_ITEM_TO_SELECT = -1;
    private int mListItemToSelect = NONE;
    static final int NONE = -1;

    // holds the maximum position that has been displayed to the user
    int mMaxDisplayed = NONE;

    // holds the position that, when displayed, should result in notifying the cursor
    int mDisplayNotifyPos = NONE;

    public SuggestionsAdapter(Context context, SearchDialog searchDialog, SearchableInfo searchable,
            WeakHashMap<String, Drawable> outsideDrawablesCache, boolean globalSearchMode) {
@@ -127,6 +127,11 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
    @Override
    public void changeCursor(Cursor c) {
        if (DBG) Log.d(LOG_TAG, "changeCursor(" + c + ")");

        if (mCursor != null) {
            callCursorPreClose(mCursor);
        }

        super.changeCursor(c);
        if (c != null) {
            mFormatCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT);
@@ -135,39 +140,69 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
            mIconName1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1);
            mIconName2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2);
        }
        updateWorking();
    }

    /**
     * Handle sending and receiving information associated with
     * {@link DialogCursorProtocol#PRE_CLOSE}.
     *
     * @param cursor The cursor to call.
     */
    private void callCursorPreClose(Cursor cursor) {
        final Bundle request = new Bundle();
        request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.PRE_CLOSE);
        request.putInt(DialogCursorProtocol.PRE_CLOSE_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
        final Bundle response = cursor.respond(request);

        mMaxDisplayed = -1;
    }

    @Override
    public void notifyDataSetChanged() {
        if (DBG) Log.d(LOG_TAG, "notifyDataSetChanged");
        super.notifyDataSetChanged();
        updateWorking();
        if (mListItemToSelect != NO_ITEM_TO_SELECT) {

        callCursorPostRefresh(mCursor);

        // look out for the pending item we are supposed to scroll to
        if (mListItemToSelect != NONE) {
            mSearchDialog.setListSelection(mListItemToSelect);
            mListItemToSelect = NO_ITEM_TO_SELECT;
            mListItemToSelect = NONE;
        }
    }

    /**
     * Specifies the list item to select upon next call of {@link #notifyDataSetChanged()},
     * in order to let us scroll the "More results..." list item to the top of the screen
     * (or as close as it can get) when clicked.
     * Handle sending and receiving information associated with
     * {@link DialogCursorProtocol#POST_REFRESH}.
     * 
     * @param cursor The cursor to call.
     */
    public void setListItemToSelect(int index) {
        mListItemToSelect = index;
    private void callCursorPostRefresh(Cursor cursor) {
        final Bundle request = new Bundle();
        request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.POST_REFRESH);
        final Bundle response = cursor.respond(request);

        mSearchDialog.setWorking(
                response.getBoolean(DialogCursorProtocol.POST_REFRESH_RECEIVE_ISPENDING, false));

        mDisplayNotifyPos =
                response.getInt(DialogCursorProtocol.POST_REFRESH_RECEIVE_DISPLAY_NOTIFY, -1);
    }

    /**
     * Updates the search dialog according to the current working status of the cursor.
     * Tell the cursor which position was clicked, handling sending and receiving information
     * associated with {@link DialogCursorProtocol#CLICK}.
     *
     * @param cursor The cursor
     * @param position The position that was clicked.
     */
    private void updateWorking() {
        if (!mGlobalSearchMode || mCursor == null) return;
        
        Bundle request = new Bundle();
        request.putString(SearchManager.RESPOND_EXTRA_PENDING_SOURCES, "DUMMY");
        Bundle response = mCursor.respond(request);

        mSearchDialog.setWorking(response.getBoolean(SearchManager.RESPOND_EXTRA_PENDING_SOURCES));
    void callCursorOnClick(Cursor cursor, int position) {
        final Bundle request = new Bundle(1);
        request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.CLICK);
        request.putInt(DialogCursorProtocol.CLICK_SEND_POSITION, position);
        final Bundle response = cursor.respond(request);
        mListItemToSelect = response.getInt(
                DialogCursorProtocol.CLICK_RECEIVE_SELECTED_POS, SuggestionsAdapter.NONE);
    }

    /**
@@ -201,11 +236,22 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        ChildViewCache views = (ChildViewCache) view.getTag();
        boolean isHtml = false;
        if (mFormatCol >= 0) {
            String format = cursor.getString(mFormatCol);
            isHtml = "html".equals(format);    
        final int pos = cursor.getPosition();

        // update the maximum position displayed since last refresh
        if (pos > mMaxDisplayed) {
            mMaxDisplayed = pos;
        }

        // if the cursor wishes to be notified about this position, send it
        if (mDisplayNotifyPos != NONE && pos == mDisplayNotifyPos) {
            final Bundle request = new Bundle();
            request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.THRESH_HIT);
            mCursor.respond(request);
            mDisplayNotifyPos = NONE;  // only notify the first time
        }

        final boolean isHtml = mFormatCol > 0 && "html".equals(cursor.getString(mFormatCol));
        setViewText(cursor, views.mText1, mText1Col, isHtml);
        setViewText(cursor, views.mText2, mText2Col, isHtml);
        setViewIcon(cursor, views.mIcon1, mIconName1Col);
@@ -400,7 +446,7 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
     */
    public static String getColumnString(Cursor cursor, String columnName) {
        int col = cursor.getColumnIndex(columnName);
        if (col == NO_ITEM_TO_SELECT) {
        if (col == NONE) {
            return null;
        }
        return cursor.getString(col);