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

Commit 5e23cbc6 authored by Satish Sampath's avatar Satish Sampath Committed by The Android Open Source Project
Browse files

am f9acde27: Include web search providers in Searchables.

Merge commit 'f9acde27'

* commit 'f9acde27':
  Include web search providers in Searchables.
parents 78084a62 f9acde27
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -23,4 +23,7 @@ import android.server.search.SearchableInfo;
interface ISearchManager {
   SearchableInfo getSearchableInfo(in ComponentName launchActivity, boolean globalSearch);
   List<SearchableInfo> getSearchablesInGlobalSearch();
   List<SearchableInfo> getSearchablesForWebSearch();
   SearchableInfo getDefaultSearchableForWebSearch();
   void setDefaultWebSearch(in ComponentName component);
}
+54 −0
Original line number Diff line number Diff line
@@ -1416,6 +1416,16 @@ public class SearchManager
    public final static String INTENT_ACTION_WEB_SEARCH_SETTINGS
            = "android.search.action.WEB_SEARCH_SETTINGS";

    /**
     * Intent action broadcasted to inform that the searchables list or default have changed.
     * Components should handle this intent if they cache any searchable data and wish to stay
     * up to date on changes.
     *
     * @hide Pending API council approval.
     */
    public final static String INTENT_ACTION_SEARCHABLES_CHANGED
            = "android.search.action.SEARCHABLES_CHANGED";

    /**
     * If a suggestion has this value in {@link #SUGGEST_COLUMN_INTENT_ACTION},
     * the search dialog will take no action.
@@ -1744,4 +1754,48 @@ public class SearchManager
            return null;
        }
    }

    /**
     * Returns a list of the searchable activities that handle web searches.
     *
     * @return a a list of all searchable activities that handle {@link SearchManager#ACTION_WEB_SEARCH}.
     *
     * @hide because SearchableInfo is not part of the API.
     */
    public static List<SearchableInfo> getSearchablesForWebSearch() {
        try {
            return sService.getSearchablesForWebSearch();
        } catch (RemoteException 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 static SearchableInfo getDefaultSearchableForWebSearch() {
        try {
            return sService.getDefaultSearchableForWebSearch();
        } catch (RemoteException 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 static void setDefaultWebSearch(ComponentName component) {
        try {
            sService.setDefaultWebSearch(component);
        } catch (RemoteException e) {
        }
    }
}
+35 −12
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.RemoteException;

import java.util.List;

@@ -150,4 +151,26 @@ public class SearchManagerService extends ISearchManager.Stub
        return mSearchables.getSearchablesInGlobalSearchList();
    }

    /**
     * Returns a list of the searchable activities that handle web searches.
     */
    public List<SearchableInfo> getSearchablesForWebSearch() {
        updateSearchablesIfDirty();
        return mSearchables.getSearchablesForWebSearchList();
    }

    /**
     * Returns the default searchable activity for web searches.
     */
    public SearchableInfo getDefaultSearchableForWebSearch() {
        updateSearchablesIfDirty();
        return mSearchables.getDefaultSearchableForWebSearch();
    }

    /**
     * Sets the default searchable activity for web searches.
     */
    public void setDefaultWebSearch(ComponentName component) {
        mSearchables.setDefaultWebSearch(component);
    }
}
+179 −49
Original line number Diff line number Diff line
@@ -16,13 +16,18 @@

package android.server.search;

import com.android.internal.app.ResolverActivity;
import com.android.internal.R;

import android.app.SearchManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.Bundle;
import android.util.Log;

@@ -48,7 +53,9 @@ public class Searchables {
    private HashMap<ComponentName, SearchableInfo> mSearchablesMap = null;
    private ArrayList<SearchableInfo> mSearchablesList = null;
    private ArrayList<SearchableInfo> mSearchablesInGlobalSearchList = null;
    private ArrayList<SearchableInfo> mSearchablesForWebSearchList = null;
    private SearchableInfo mDefaultSearchable = null;
    private SearchableInfo mDefaultSearchableForWebSearch = null;

    /**
     *
@@ -169,7 +176,7 @@ public class Searchables {
    /**
     * Builds an entire list (suitable for display) of
     * activities that are searchable, by iterating the entire set of
     * ACTION_SEARCH intents.  
     * ACTION_SEARCH & ACTION_WEB_SEARCH intents.
     *
     * Also clears the hash of all activities -> searches which will
     * refill as the user clicks "search".
@@ -194,21 +201,33 @@ public class Searchables {
                                = new ArrayList<SearchableInfo>();
        ArrayList<SearchableInfo> newSearchablesInGlobalSearchList
                                = new ArrayList<SearchableInfo>();
        ArrayList<SearchableInfo> newSearchablesForWebSearchList
                                = new ArrayList<SearchableInfo>();

        final PackageManager pm = mContext.getPackageManager();

        // use intent resolver to generate list of ACTION_SEARCH receivers
        List<ResolveInfo> infoList;
        // Use intent resolver to generate list of ACTION_SEARCH & ACTION_WEB_SEARCH receivers.
        List<ResolveInfo> searchList;
        final Intent intent = new Intent(Intent.ACTION_SEARCH);
        infoList = pm.queryIntentActivities(intent, PackageManager.GET_META_DATA);
        searchList = pm.queryIntentActivities(intent, PackageManager.GET_META_DATA);

        List<ResolveInfo> webSearchInfoList;
        final Intent webSearchIntent = new Intent(Intent.ACTION_WEB_SEARCH);
        webSearchInfoList = pm.queryIntentActivities(webSearchIntent, PackageManager.GET_META_DATA);

        // analyze each one, generate a Searchables record, and record
        if (infoList != null) {
            int count = infoList.size();
        if (searchList != null || webSearchInfoList != null) {
            int search_count = (searchList == null ? 0 : searchList.size());
            int web_search_count = (webSearchInfoList == null ? 0 : webSearchInfoList.size());
            int count = search_count + web_search_count;
            for (int ii = 0; ii < count; ii++) {
                // for each component, try to find metadata
                ResolveInfo info = infoList.get(ii);
                ResolveInfo info = (ii < search_count)
                        ? searchList.get(ii)
                        : webSearchInfoList.get(ii - search_count);
                ActivityInfo ai = info.activityInfo;
                // Check first to avoid duplicate entries.
                if (newSearchablesMap.get(new ComponentName(ai.packageName, ai.name)) == null) {
                    SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai);
                    if (searchable != null) {
                        newSearchablesList.add(searchable);
@@ -219,6 +238,15 @@ public class Searchables {
                    }
                }
            }
        }

        if (webSearchInfoList != null) {
            for (int i = 0; i < webSearchInfoList.size(); ++i) {
                ActivityInfo ai = webSearchInfoList.get(i).activityInfo;
                ComponentName component = new ComponentName(ai.packageName, ai.name);
                newSearchablesForWebSearchList.add(newSearchablesMap.get(component));
            }
        }

        // Find the global search provider
        Intent globalSearchIntent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
@@ -230,13 +258,93 @@ public class Searchables {
                    + globalSearchActivity);
        }

        // Find the default web search provider.
        ComponentName webSearchActivity = getPreferredWebSearchActivity();
        SearchableInfo newDefaultSearchableForWebSearch = null;
        if (webSearchActivity != null) {
            newDefaultSearchableForWebSearch = newSearchablesMap.get(webSearchActivity);
        }
        if (newDefaultSearchableForWebSearch == null) {
            Log.w(LOG_TAG, "No searchable info found for new default web search activity "
                    + webSearchActivity);
        }

        // Store a consistent set of new values
        synchronized (this) {
            mSearchablesMap = newSearchablesMap;
            mSearchablesList = newSearchablesList;
            mSearchablesInGlobalSearchList = newSearchablesInGlobalSearchList;
            mSearchablesForWebSearchList = newSearchablesForWebSearchList;
            mDefaultSearchable = newDefaultSearchable;
            mDefaultSearchableForWebSearch = newDefaultSearchableForWebSearch;
        }

        // Inform all listeners that the list of searchables has been updated.
        mContext.sendBroadcast(new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED));
    }

    /**
     * Checks if the given activity component is present in the system and if so makes it the
     * preferred activity for handling ACTION_WEB_SEARCH.
     * @param component Name of the component to check and set as preferred.
     * @param action Intent action for which this activity is to be set as preferred.
     * @return true if component was detected and set as preferred activity, false if not.
     */
    private boolean setPreferredActivity(ComponentName component, String action) {
        Log.d(LOG_TAG, "Checking component " + component);
        PackageManager pm = mContext.getPackageManager();
        ActivityInfo ai;
        try {
            ai = pm.getActivityInfo(component, 0);
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }

        // The code here to find the value for bestMatch is heavily inspired by the code
        // in ResolverActivity where the preferred activity is set.
        Intent intent = new Intent(action);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        List<ResolveInfo> webSearchActivities = pm.queryIntentActivities(intent, 0);
        ComponentName set[] = new ComponentName[webSearchActivities.size()];
        int bestMatch = 0;
        for (int i = 0; i < webSearchActivities.size(); ++i) {
            ResolveInfo ri = webSearchActivities.get(i);
            set[i] = new ComponentName(ri.activityInfo.packageName,
                                       ri.activityInfo.name);
            if (ri.match > bestMatch) bestMatch = ri.match;
        }

        Log.d(LOG_TAG, "Setting preferred web search activity to " + component);
        IntentFilter filter = new IntentFilter(action);
        filter.addCategory(Intent.CATEGORY_DEFAULT);
        pm.replacePreferredActivity(filter, bestMatch, set, component);
        return true;
    }

    public ComponentName getPreferredWebSearchActivity() {
        // Check if we have a preferred web search activity.
        Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
        PackageManager pm = mContext.getPackageManager();
        ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);

        if (ri == null || ri.activityInfo.name.equals(ResolverActivity.class.getName())) {
            Log.d(LOG_TAG, "No preferred activity set for action web search.");

            // The components in the providers array are checked in the order of declaration so the
            // first one has the highest priority. If the component exists in the system it is set
            // as the preferred activity to handle intent action web search.
            String[] preferredActivities = mContext.getResources().getStringArray(
                    com.android.internal.R.array.default_web_search_providers);
            for (String componentName : preferredActivities) {
                ComponentName component = ComponentName.unflattenFromString(componentName);
                if (setPreferredActivity(component, Intent.ACTION_WEB_SEARCH)) {
                    return component;
                }
            }
        }

        if (ri == null) return null;
        return new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name);
    }

    /**
@@ -253,4 +361,26 @@ public class Searchables {
    public synchronized ArrayList<SearchableInfo> getSearchablesInGlobalSearchList() {
        return new ArrayList<SearchableInfo>(mSearchablesInGlobalSearchList);
    }

    /**
     * Returns a list of the searchable activities that handle web searches.
     */
    public synchronized ArrayList<SearchableInfo> getSearchablesForWebSearchList() {
        return new ArrayList<SearchableInfo>(mSearchablesForWebSearchList);
    }

    /**
     * Returns the default searchable activity for web searches.
     */
    public synchronized SearchableInfo getDefaultSearchableForWebSearch() {
        return mDefaultSearchableForWebSearch;
    }

    /**
     * Sets the default searchable activity for web searches.
     */
    public synchronized void setDefaultWebSearch(ComponentName component) {
        setPreferredActivity(component, Intent.ACTION_WEB_SEARCH);
        buildSearchableList();
    }
}
+10 −0
Original line number Diff line number Diff line
@@ -125,4 +125,14 @@
        <item><xliff:g id="id">sync_failing</xliff:g></item>
        <item><xliff:g id="id">ime</xliff:g></item>
    </string-array>

    <!-- Do not translate. Each string points to the component name of an ACTION_WEB_SEARCH
         handling activity. On startup if there were no preferred ACTION_WEB_SEARCH handlers,
         the first component from this list which is found to be installed is set as the
         preferred activity. -->
    <string-array name="default_web_search_providers">
        <item>com.google.android.providers.genie/.GenieLauncher</item>
        <item>com.android.googlesearch/.GoogleSearch</item>
        <item>com.android.websearch/.Search.1</item>
    </string-array>
</resources>
Loading