Merge "Fix build failure"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 543c90b..da88f76 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2558,6 +2558,7 @@
             <intent-filter android:priority="1">
                 <action android:name="com.android.settings.SOUND_SETTINGS" />
                 <action android:name="android.settings.SOUND_SETTINGS" />
+                <action android:name="android.settings.ACTION_OTHER_SOUND_SETTINGS" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
             <intent-filter>
@@ -2566,10 +2567,6 @@
                 <category android:name="android.intent.category.VOICE_LAUNCH" />
                 <category android:name="com.android.settings.SHORTCUT" />
             </intent-filter>
-            <intent-filter android:priority="1">
-                <action android:name="android.settings.ACTION_OTHER_SOUND_SETTINGS" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
             <intent-filter android:priority="6">
                 <action android:name="com.android.settings.action.SETTINGS" />
             </intent-filter>
diff --git a/src/com/android/settings/search2/IntentSearchViewHolder.java b/src/com/android/settings/search2/IntentSearchViewHolder.java
index f0cbc51..0596397 100644
--- a/src/com/android/settings/search2/IntentSearchViewHolder.java
+++ b/src/com/android/settings/search2/IntentSearchViewHolder.java
@@ -51,6 +51,7 @@
             mMetricsFeatureProvider.action(v.getContext(),
                     MetricsEvent.ACTION_CLICK_SETTINGS_SEARCH_RESULT,
                     resultName, rank);
+            mSearchFeatureProvider.searchResultClicked(fragment.mQuery, result);
             fragment.startActivity(intent);
         });
     }
diff --git a/src/com/android/settings/search2/SearchFeatureProvider.java b/src/com/android/settings/search2/SearchFeatureProvider.java
index d3dc24b..e77a332 100644
--- a/src/com/android/settings/search2/SearchFeatureProvider.java
+++ b/src/com/android/settings/search2/SearchFeatureProvider.java
@@ -22,6 +22,8 @@
 import android.view.View;
 import com.android.settings.dashboard.SiteMapManager;
 
+import java.util.List;
+
 /**
  * FeatureProvider for Settings Search
  */
@@ -89,5 +91,29 @@
     default void hideFeedbackButton() {
     }
 
+    /**
+     * Ranks search results based on the input query.
+     *
+     * @param query input user query
+     * @param searchResults list of search results to be ranked
+     */
+    default void rankSearchResults(String query, List<SearchResult> searchResults) {
+    }
+
+    /**
+     * Notify that a search result is clicked.
+     *
+     * @param query input user query
+     * @param searchResult clicked result
+     */
+    default void searchResultClicked(String query, SearchResult searchResult) {
+    }
+
+    /**
+     * @return true to enable search ranking.
+     */
+    default boolean isSmartSearchRankingEnabled(Context context) {
+        return false;
+    }
 
 }
diff --git a/src/com/android/settings/search2/SearchFragment.java b/src/com/android/settings/search2/SearchFragment.java
index 8e1e1b4..a8d219c 100644
--- a/src/com/android/settings/search2/SearchFragment.java
+++ b/src/com/android/settings/search2/SearchFragment.java
@@ -117,7 +117,7 @@
         super.onCreate(savedInstanceState);
         setHasOptionsMenu(true);
         final LoaderManager loaderManager = getLoaderManager();
-        mSearchAdapter = new SearchResultsAdapter(this);
+        mSearchAdapter = new SearchResultsAdapter(this, mSearchFeatureProvider);
         mSavedQueryController = new SavedQueryController(
                 getContext(), loaderManager, mSearchAdapter);
         mSearchFeatureProvider.initFeedbackButton();
@@ -251,7 +251,7 @@
         if (mUnfinishedLoadersCount.decrementAndGet() != 0) {
             return;
         }
-        final int resultCount = mSearchAdapter.displaySearchResults();
+        final int resultCount = mSearchAdapter.displaySearchResults(mQuery);
         mNoResultsView.setVisibility(resultCount == 0 ? View.VISIBLE : View.GONE);
         mSearchFeatureProvider.showFeedbackButton(this, getView());
     }
diff --git a/src/com/android/settings/search2/SearchResultsAdapter.java b/src/com/android/settings/search2/SearchResultsAdapter.java
index 6ff68b1..d0ea5bf 100644
--- a/src/com/android/settings/search2/SearchResultsAdapter.java
+++ b/src/com/android/settings/search2/SearchResultsAdapter.java
@@ -40,11 +40,14 @@
     private final List<SearchResult> mSearchResults;
     private final SearchFragment mFragment;
     private Map<String, List<? extends SearchResult>> mResultsMap;
+    private final SearchFeatureProvider mSearchFeatureProvider;
 
-    public SearchResultsAdapter(SearchFragment fragment) {
+    public SearchResultsAdapter(SearchFragment fragment,
+            SearchFeatureProvider searchFeatureProvider) {
         mFragment = fragment;
         mSearchResults = new ArrayList<>();
         mResultsMap = new ArrayMap<>();
+        mSearchFeatureProvider = searchFeatureProvider;
 
         setHasStableIds(true);
     }
@@ -119,9 +122,10 @@
      * Merge the results from each of the loaders into one list for the adapter.
      * Prioritizes results from the local database over installed apps.
      *
+     * @param query user query corresponding to these results
      * @return Number of matched results
      */
-    public int displaySearchResults() {
+    public int displaySearchResults(String query) {
         final List<? extends SearchResult> databaseResults = mResultsMap
                 .get(DatabaseResultLoader.class.getName());
         final List<? extends SearchResult> installedAppResults = mResultsMap
@@ -151,6 +155,12 @@
             results.add(installedAppResults.get(appIndex++));
         }
 
+        if (mSearchFeatureProvider
+                .isSmartSearchRankingEnabled(mFragment.getContext().getApplicationContext())) {
+            // TODO: run this in parallel to loading the results if takes too long
+            mSearchFeatureProvider.rankSearchResults(query, results);
+        }
+
         mSearchResults.addAll(results);
         notifyDataSetChanged();
 
diff --git a/src/com/android/settings/search2/SearchViewHolder.java b/src/com/android/settings/search2/SearchViewHolder.java
index 123a602..1439833 100644
--- a/src/com/android/settings/search2/SearchViewHolder.java
+++ b/src/com/android/settings/search2/SearchViewHolder.java
@@ -40,11 +40,14 @@
     public final ImageView iconView;
 
     protected final MetricsFeatureProvider mMetricsFeatureProvider;
+    protected final SearchFeatureProvider mSearchFeatureProvider;
 
     public SearchViewHolder(View view) {
         super(view);
-        mMetricsFeatureProvider = FeatureFactory.getFactory(view.getContext())
-                .getMetricsFeatureProvider();
+        final FeatureFactory featureFactory = FeatureFactory
+                .getFactory(view.getContext().getApplicationContext());
+        mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
+        mSearchFeatureProvider = featureFactory.getSearchFeatureProvider();
         titleView = view.findViewById(android.R.id.title);
         summaryView = view.findViewById(android.R.id.summary);
         iconView = view.findViewById(android.R.id.icon);
diff --git a/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java b/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java
index 647d68c..f5a29ce 100644
--- a/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java
@@ -34,6 +34,7 @@
 import com.android.settings.search2.IntentPayload;
 import com.android.settings.search2.IntentSearchViewHolder;
 import com.android.settings.search2.ResultPayload;
+import com.android.settings.search2.SearchFeatureProvider;
 import com.android.settings.search2.SearchFragment;
 import com.android.settings.search2.SearchResult;
 import com.android.settings.search2.SearchResult.Builder;
@@ -48,6 +49,14 @@
 import org.robolectric.Robolectric;
 import org.robolectric.annotation.Config;
 
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyList;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -59,6 +68,10 @@
 
     @Mock
     private SearchFragment mFragment;
+    @Mock
+    private SearchFeatureProvider mSearchFeatureProvider;
+    @Mock
+    private Context mMockContext;
     private SearchResultsAdapter mAdapter;
     private Context mContext;
     private String mLoaderClassName;
@@ -67,8 +80,10 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = Robolectric.buildActivity(Activity.class).get();
-        mAdapter = new SearchResultsAdapter(mFragment);
+        mAdapter = new SearchResultsAdapter(mFragment, mSearchFeatureProvider);
         mLoaderClassName = DatabaseResultLoader.class.getName();
+        when(mFragment.getContext()).thenReturn(mMockContext);
+        when(mMockContext.getApplicationContext()).thenReturn(mContext);
     }
 
     @Test
@@ -81,7 +96,7 @@
     public void testSingleSourceMerge_ExactCopyReturned() {
         ArrayList<SearchResult> intentResults = getIntentSampleResults();
         mAdapter.addSearchResults(intentResults, mLoaderClassName);
-        mAdapter.displaySearchResults();
+        mAdapter.displaySearchResults("");
 
         List<SearchResult> updatedResults = mAdapter.getSearchResults();
         assertThat(updatedResults).containsAllIn(intentResults);
@@ -109,7 +124,7 @@
                 InstalledAppResultLoader.class.getName());
         mAdapter.addSearchResults(getDummyDbResults(),
                 DatabaseResultLoader.class.getName());
-        int count = mAdapter.displaySearchResults();
+        int count = mAdapter.displaySearchResults("");
 
         List<SearchResult> results = mAdapter.getSearchResults();
         assertThat(results.get(0).title).isEqualTo("alpha");
@@ -121,6 +136,22 @@
         assertThat(count).isEqualTo(6);
     }
 
+    @Test
+    public void testDisplayResults_ShouldNotRunSmartRankingIfDisabled() {
+        when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any()))
+            .thenReturn(false);
+        mAdapter.displaySearchResults("");
+        verify(mSearchFeatureProvider, never()).rankSearchResults(anyString(), anyList());
+    }
+
+    @Test
+    public void testDisplayResults_ShouldRunSmartRankingIfEnabled() {
+        when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any()))
+            .thenReturn(true);
+        mAdapter.displaySearchResults("");
+        verify(mSearchFeatureProvider, times(1)).rankSearchResults(anyString(), anyList());
+    }
+
     private List<SearchResult> getDummyDbResults() {
         List<SearchResult> results = new ArrayList<>();
         IntentPayload payload = new IntentPayload(new Intent());