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

Commit 479ae0a2 authored by Amith Yamasani's avatar Amith Yamasani
Browse files

Cleanup of global search references in SearchDialog and SearchManager.

parent 1e84ac51
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -822,11 +822,6 @@ public class Dialog implements DialogInterface, Window.Callback,
        final SearchManager searchManager = (SearchManager) mContext
                .getSystemService(Context.SEARCH_SERVICE);

        // can't start search without an associated activity (e.g a system dialog)
        if (!searchManager.hasIdent()) {
            return false;
        }

        // associate search with owner activity if possible (otherwise it will default to
        // global search).
        final ComponentName appName = getAssociatedActivity();
+57 −509

File changed.

Preview size limit exceeded, changes collapsed.

+12 −223
Original line number Diff line number Diff line
@@ -360,7 +360,8 @@ import java.util.List;
 * 
 * <p>Every query includes a Uri, and the Search Manager will format the Uri as shown:
 * <p><pre class="prettyprint">
 * content:// your.suggest.authority / your.suggest.path / SearchManager.SUGGEST_URI_PATH_QUERY</pre>
 * content:// your.suggest.authority / your.suggest.path / SearchManager.SUGGEST_URI_PATH_QUERY
 *    </pre>
 * 
 * <p>Your Content Provider can receive the query text in one of two ways.
 * <ul>
@@ -546,7 +547,8 @@ import java.util.List;
 * taken directly to a specific result.
 *   <ul>
 *   <li><b>Action:</b> {@link android.content.Intent#ACTION_VIEW ACTION_VIEW}</li>
 *   <li><b>Data:</b> a complete Uri, supplied by the cursor, that identifies the desired data.</li>
 *   <li><b>Data:</b> a complete Uri, supplied by the cursor, that identifies the desired data.
 *   </li>
 *   <li><b>Query:</b> query text supplied with the suggestion (probably ignored)</li>
 *   </ul>
 * </li>
@@ -1288,15 +1290,6 @@ public class SearchManager
     */
    public final static String SEARCH_MODE = "search_mode";

    /**
     * Value for the {@link #SEARCH_MODE} key.
     * This is used if the intent was launched by clicking a suggestion in global search
     * mode (Quick Search Box).
     *
     * @hide
     */
    public static final String MODE_GLOBAL_SEARCH_SUGGESTION = "global_search_suggestion";

    /**
     * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
     * {@link android.content.Intent#getIntExtra content.Intent.getIntExtra()}
@@ -1307,14 +1300,6 @@ public class SearchManager
     */
    public final static String ACTION_KEY = "action_key";
    
    /**
     * Intent component name key: This key will be used for the extra populated by the
     * {@link #SUGGEST_COLUMN_INTENT_COMPONENT_NAME} column.
     *
     * {@hide}
     */
    public final static String COMPONENT_NAME_KEY = "intent_component_name_key";

    /**
     * Intent extra data key: This key will be used for the extra populated by the
     * {@link #SUGGEST_COLUMN_INTENT_EXTRA_DATA} column.
@@ -1328,58 +1313,6 @@ public class SearchManager
     */
    public final static String EXTRA_SELECT_QUERY = "select_query";

    /**
     * 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
     */
    public static class DialogCursorProtocol {

        /**
         * The sent bundle will contain this integer key, with a value set to one of the events
         * below.
         */
        public final static String METHOD = "DialogCursorProtocol.method";

        /**
         * After data has been refreshed.
         */
        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";

        /**
         * 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_SEND_MAX_DISPLAY_POS
                = "DialogCursorProtocol.CLICK.sendDisplayPosition";
        public final static String CLICK_SEND_ACTION_KEY
                = "DialogCursorProtocol.CLICK.sendActionKey";
        public final static String CLICK_SEND_ACTION_MSG
                = "DialogCursorProtocol.CLICK.sendActionMsg";
        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;

        /**
         * When a search is started without using a suggestion.
         */
        public final static int SEARCH = 4;
        public final static String SEARCH_SEND_MAX_DISPLAY_POS
                = "DialogCursorProtocol.SEARCH.sendDisplayPosition";
        public final static String SEARCH_SEND_QUERY = "DialogCursorProtocol.SEARCH.query";
    }

    /**
     * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
     * {@link android.content.Intent#getStringExtra content.Intent.getStringExtra()}
@@ -1421,40 +1354,6 @@ public class SearchManager
    public final static String SHORTCUT_MIME_TYPE = 
            "vnd.android.cursor.item/vnd.android.search.suggest";


    /**
     * The authority of the provider to report clicks to when a click is detected after pivoting
     * into a specific app's search from global search.
     *
     * In addition to the columns below, the suggestion columns are used to pass along the full
     * suggestion so it can be shortcutted.
     *
     * @hide
     */
    public final static String SEARCH_CLICK_REPORT_AUTHORITY =
            "com.android.globalsearch.stats";

    /**
     * The path the write goes to.
     *
     * @hide
     */
    public final static String SEARCH_CLICK_REPORT_URI_PATH = "click";

    /**
     * The column storing the query for the click.
     *
     * @hide
     */
    public final static String SEARCH_CLICK_REPORT_COLUMN_QUERY = "query";

    /**
     * The column storing the component name of the application that was pivoted into.
     *
     * @hide
     */
    public final static String SEARCH_CLICK_REPORT_COLUMN_COMPONENT = "component";

    /**
     * Column name for suggestions cursor.  <i>Unused - can be null or column can be omitted.</i>
     */
@@ -1531,10 +1430,7 @@ public class SearchManager
     */
    public final static String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
    /**
     * Column name for suggestions cursor.  <i>Optional.</i>  This column allows suggestions
     *  to provide additional arbitrary data which will be included as an extra under the key
     *  {@link #COMPONENT_NAME_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.
     * TODO: Remove
     *
     * @hide
     */
@@ -1593,27 +1489,6 @@ public class SearchManager
     */
    public final static String SUGGEST_PARAMETER_LIMIT = "limit";

    /**
     * If a suggestion has this value in {@link #SUGGEST_COLUMN_INTENT_ACTION},
     * the search dialog will switch to a different suggestion source when the
     * suggestion is clicked. 
     * 
     * {@link #SUGGEST_COLUMN_INTENT_DATA} must contain
     * the flattened {@link ComponentName} of the activity which is to be searched.
     * 
     * TODO: Should {@link #SUGGEST_COLUMN_INTENT_DATA} instead contain a URI in the format
     * used by {@link android.provider.Applications}?
     * 
     * TODO: This intent should be protected by the same permission that we use
     * for replacing the global search provider.
     * 
     * The query text field will be set to the value of {@link #SUGGEST_COLUMN_QUERY}.
     * 
     * @hide Pending API council approval.
     */
    public final static String INTENT_ACTION_CHANGE_SEARCH_SOURCE 
            = "android.search.action.CHANGE_SEARCH_SOURCE";

    /**
     * Intent action for starting the global search activity.
     * The global search provider should handle this intent.
@@ -1671,13 +1546,6 @@ public class SearchManager

    private final Context mContext;

    /**
     * compact representation of the activity associated with this search manager so
     * we can say who we are when starting search.  the search managerservice, in turn,
     * uses this to properly handle the back stack.
     */
    private int mIdent;

    /**
     * The package associated with this seach manager.
     */
@@ -1697,21 +1565,6 @@ public class SearchManager
                ServiceManager.getService(Context.SEARCH_SERVICE));
    }
    
    /*package*/ boolean hasIdent() {
        return mIdent != 0;
    }
    
    /*package*/ void setIdent(int ident, ComponentName component) {
        if (mIdent != 0) {
            throw new IllegalStateException("mIdent already set");
        }
        if (component == null) {
            throw new IllegalArgumentException("component must be non-null");
        }
        mIdent = ident;
        mAssociatedPackage = component.getPackageName();
    }
    
    /**
     * Launch search UI.
     *
@@ -1757,15 +1610,14 @@ public class SearchManager
                            ComponentName launchActivity,
                            Bundle appSearchData,
                            boolean globalSearch) {
        ensureSearchDialog();

        if (globalSearch) {
            startGlobalSearch(initialQuery, selectInitialQuery, appSearchData);
            return;
        }

        mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
                globalSearch);
        ensureSearchDialog();

        mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData);
    }

    private void ensureSearchDialog() {
@@ -1995,17 +1847,6 @@ public class SearchManager
        }
    }

    /**
     * Checks whether the given searchable is the default searchable.
     * 
     * @hide because SearchableInfo is not part of the API.
     */
    public boolean isDefaultSearchable(SearchableInfo searchable) {
        SearchableInfo defaultSearchable = getSearchableInfo(null, true);
        return defaultSearchable != null 
                && defaultSearchable.getSearchActivity().equals(searchable.getSearchActivity());
    }

    /**
     * Gets a cursor with search suggestions.
     *
@@ -2091,56 +1932,4 @@ public class SearchManager
        }
    }

    /**
     * Returns a list of the searchable activities that handle web searches.
     *
     * @return a list of all searchable activities that handle
     *         {@link android.content.Intent#ACTION_WEB_SEARCH}.
     *
     * @hide because SearchableInfo is not part of the API.
     */
    public List<SearchableInfo> getSearchablesForWebSearch() {
        try {
            return mService.getSearchablesForWebSearch();
        } catch (RemoteException e) {
            Log.e(TAG, "getSearchablesForWebSearch() failed: " + e);
            return null;
        }
    }

    /**
     * Returns the default searchable activity for web searches.
     *
     * @return searchable information for the activity handling web searches by default.
     *
     * @hide because SearchableInfo is not part of the API.
     */
    public SearchableInfo getDefaultSearchableForWebSearch() {
        try {
            return mService.getDefaultSearchableForWebSearch();
        } catch (RemoteException e) {
            Log.e(TAG, "getDefaultSearchableForWebSearch() failed: " + e);
            return null;
        }
    }

    /**
     * Sets the default searchable activity for web searches.
     *
     * @param component Name of the component to set as default activity for web searches.
     *
     * @hide
     */
    public void setDefaultWebSearch(ComponentName component) {
        try {
            mService.setDefaultWebSearch(component);
        } catch (RemoteException e) {
            Log.e(TAG, "setDefaultWebSearch() failed: " + e);
        }
    }

    private static void debug(String msg) {
        Thread thread = Thread.currentThread();
        Log.d(TAG, msg + " (" + thread.getName() + "-" + thread.getId() + ")");
    }
}
+9 −145
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package android.app;

import android.app.SearchManager.DialogCursorProtocol;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -30,12 +29,10 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
@@ -65,7 +62,6 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
    private Context mProviderContext;
    private WeakHashMap<String, Drawable.ConstantState> mOutsideDrawablesCache;
    private SparseArray<Drawable.ConstantState> mBackgroundsCache;
    private boolean mGlobalSearchMode;
    private boolean mClosed = false;

    // Cached column indexes, updated when the cursor changes.
@@ -76,29 +72,8 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
    private int mIconName2Col;
    private int mBackgroundColorCol;
    
    // The extra used to tell a cursor to close itself. This is a hack, see the description by
    // its use later in this file.
    private static final String EXTRA_CURSOR_RESPOND_CLOSE_CURSOR = "cursor_respond_close_cursor";

    // The bundle which contains {EXTRA_CURSOR_RESPOND_CLOSE_CURSOR=true}, just cached once
    // so we don't bother recreating it a bunch.
    private final Bundle mCursorRespondCloseCursorBundle;

    // 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 NONE every time it
    // is consumed.
    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;

    private final Runnable mStartSpinnerRunnable;
    private final Runnable mStopSpinnerRunnable;

@@ -110,8 +85,7 @@ class SuggestionsAdapter extends ResourceCursorAdapter {

    public SuggestionsAdapter(Context context, SearchDialog searchDialog,
            SearchableInfo searchable,
            WeakHashMap<String, Drawable.ConstantState> outsideDrawablesCache,
            boolean globalSearchMode) {
            WeakHashMap<String, Drawable.ConstantState> outsideDrawablesCache) {
        super(context,
                com.android.internal.R.layout.search_dropdown_item_icons_2line,
                null,   // no initial cursor
@@ -126,7 +100,6 @@ class SuggestionsAdapter extends ResourceCursorAdapter {

        mOutsideDrawablesCache = outsideDrawablesCache;
        mBackgroundsCache = new SparseArray<Drawable.ConstantState>();
        mGlobalSearchMode = globalSearchMode;

        mStartSpinnerRunnable = new Runnable() {
                public void run() {
@@ -140,10 +113,6 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
            }
        };
        
        // Create this once because we'll reuse it a bunch.
        mCursorRespondCloseCursorBundle = new Bundle();
        mCursorRespondCloseCursorBundle.putBoolean(EXTRA_CURSOR_RESPOND_CLOSE_CURSOR, true);

        // delay 500ms when deleting
        getFilter().setDelayer(new Filter.Delayer() {

@@ -177,29 +146,24 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
    public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
        if (DBG) Log.d(LOG_TAG, "runQueryOnBackgroundThread(" + constraint + ")");
        String query = (constraint == null) ? "" : constraint.toString();
        if (!mGlobalSearchMode) {
        /**
         * for in app search we show the progress spinner until the cursor is returned with
             * the results.  for global search we manage the progress bar using
             * {@link DialogCursorProtocol#POST_REFRESH_RECEIVE_ISPENDING}.
         * the results.
         */
        mSearchDialog.getWindow().getDecorView().post(mStartSpinnerRunnable);
        }
        try {
            final Cursor cursor = mSearchManager.getSuggestions(mSearchable, query, QUERY_LIMIT);
            // trigger fill window so the spinner stays up until the results are copied over and
            // closer to being ready
            if (!mGlobalSearchMode && cursor != null) cursor.getCount();
            if (cursor != null) cursor.getCount();
            return cursor;
        } catch (RuntimeException e) {
            Log.w(LOG_TAG, "Search suggestions query threw an exception.", e);
            return null;
        } finally {
            if (!mGlobalSearchMode) {
            mSearchDialog.getWindow().getDecorView().post(mStopSpinnerRunnable);
        }
    }
    }

    public void close() {
        if (DBG) Log.d(LOG_TAG, "close()");
@@ -221,21 +185,8 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
        }

        try {
            Cursor oldCursor = getCursor();
            super.changeCursor(c);

            // We send a special respond to the cursor to tell it to close itself directly because
            // it may not happen correctly for some cursors currently. This was originally
            // included as a fix to http://b/2036290, in which the search dialog was holding
            // on to references to the web search provider unnecessarily. This is being caused by
            // the fact that the cursor is not being correctly closed in
            // BulkCursorToCursorAdapter#close, which remains unfixed (see http://b/2015069).
            //
            // TODO: Remove this hack once http://b/2015069 is fixed.
            if (oldCursor != null && oldCursor != c) {
                oldCursor.respond(mCursorRespondCloseCursorBundle);
            }
            
            if (c != null) {
                mFormatCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT);
                mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1);
@@ -249,79 +200,6 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
        }
    }

    @Override
    public void notifyDataSetChanged() {
        if (DBG) Log.d(LOG_TAG, "notifyDataSetChanged");
        super.notifyDataSetChanged();

        callCursorPostRefresh(mCursor);

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

    /**
     * Handle sending and receiving information associated with
     * {@link DialogCursorProtocol#POST_REFRESH}.
     *
     * @param cursor The cursor to call.
     */
    private void callCursorPostRefresh(Cursor cursor) {
        if (!mGlobalSearchMode) return;
        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);
    }

    /**
     * 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.
     */
    void callCursorOnClick(Cursor cursor, int position, int actionKey, String actionMsg) {
        if (!mGlobalSearchMode) return;
        final Bundle request = new Bundle(5);
        request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.CLICK);
        request.putInt(DialogCursorProtocol.CLICK_SEND_POSITION, position);
        request.putInt(DialogCursorProtocol.CLICK_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
        if (actionKey != KeyEvent.KEYCODE_UNKNOWN) {
            request.putInt(DialogCursorProtocol.CLICK_SEND_ACTION_KEY, actionKey);
            request.putString(DialogCursorProtocol.CLICK_SEND_ACTION_MSG, actionMsg);
        }
        final Bundle response = cursor.respond(request);
        mMaxDisplayed = -1;
        mListItemToSelect = response.getInt(
                DialogCursorProtocol.CLICK_RECEIVE_SELECTED_POS, SuggestionsAdapter.NONE);
    }

    /**
     * Tell the cursor that a search was started without using a suggestion.
     *
     * @param query The search query.
     */
    void reportSearch(String query) {
        if (!mGlobalSearchMode) return;
        Cursor cursor = getCursor();
        if (cursor == null) return;
        final Bundle request = new Bundle(3);
        request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.SEARCH);
        request.putString(DialogCursorProtocol.SEARCH_SEND_QUERY, query);
        request.putInt(DialogCursorProtocol.SEARCH_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
        // the response is always empty
        cursor.respond(request);
    }

    /**
     * Tags the view with cached child view look-ups.
     */
@@ -353,20 +231,6 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        ChildViewCache views = (ChildViewCache) view.getTag();
        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 (mGlobalSearchMode && 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
        }

        int backgroundColor = 0;
        if (mBackgroundColorCol != -1) {
+0 −17
Original line number Diff line number Diff line
@@ -120,23 +120,6 @@ public class SearchManagerTest extends ActivityInstrumentationTestCase2<LocalAct
        assertSame(searchManager1, searchManager2 );
    }

    @MediumTest
    public void testSearchables() {
        SearchManager searchManager = (SearchManager)
                mContext.getSystemService(Context.SEARCH_SERVICE);
        SearchableInfo si;

        si = searchManager.getSearchableInfo(SEARCHABLE_ACTIVITY, false);
        assertNotNull(si);
        assertFalse(searchManager.isDefaultSearchable(si));
        si = searchManager.getSearchableInfo(SEARCHABLE_ACTIVITY, true);
        assertNotNull(si);
        assertTrue(searchManager.isDefaultSearchable(si));
        si = searchManager.getSearchableInfo(null, true);
        assertNotNull(si);
        assertTrue(searchManager.isDefaultSearchable(si));
    }

    /**
     * Tests that startSearch() can be called multiple times without stopSearch()
     * in between.