Settings now collects search results from a single loader which fetches from an aggregator. This is to facilitate the separation of search functionalitiy, where "query" becomes a single synchronous call. In this case, the aggregator will move to the unbundled app and would be called on the other end of the Query call. i.e. the new search result loader will just call query, and unbundled search will handle everything else. An important implication is that the results will be returned in a ranked order. Thus the ranking and merging logic has been moved out of the RecyclerView adapter (which is a good clean-up, anyway). The SearchResultAggregator starts a Future for each of the data sources: - Static Results - Installed Apps - Input Devices - Accessibility Services We allow up to 500ms to collect the static results, and then an additional 150ms for each subsequent loader. In my quick tests, the static results take about 20-30ms to load. The longest loader is installed apps which takes roughly 50-60ms seconds (note that this will be improved with dynamic result caching). To handle the ranking in DatabaseResultLoader, we start a Future to collect the dynamic ranking before we start the SQL queries. When the SQL is done, we wait the same timeout as before. Then we merge the results, as before. For now we have not changed how the Dynamic results are collected, but eventually they will be a cache of dynamic results. Bug: 33577327 Bug: 67360547 Test: robotests Change-Id: I91fb03f9fd059672a970f48bea21c8d655007fa3
103 lines
3.4 KiB
Java
103 lines
3.4 KiB
Java
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
package com.android.settings.search;
|
|
|
|
import static com.google.common.truth.Truth.assertThat;
|
|
|
|
import android.app.Activity;
|
|
import android.content.ComponentName;
|
|
import com.android.settings.TestConfig;
|
|
import com.android.settings.dashboard.SiteMapManager;
|
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
|
|
|
import org.junit.Before;
|
|
import org.junit.Test;
|
|
import org.junit.runner.RunWith;
|
|
import org.mockito.MockitoAnnotations;
|
|
import org.robolectric.Robolectric;
|
|
import org.robolectric.annotation.Config;
|
|
|
|
import static org.mockito.ArgumentMatchers.eq;
|
|
import static org.mockito.Mockito.spy;
|
|
import static org.mockito.Mockito.verify;
|
|
|
|
@RunWith(SettingsRobolectricTestRunner.class)
|
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
|
public class SearchFeatureProviderImplTest {
|
|
private SearchFeatureProviderImpl mProvider;
|
|
private Activity mActivity;
|
|
|
|
@Before
|
|
public void setUp() {
|
|
MockitoAnnotations.initMocks(this);
|
|
mActivity = Robolectric.buildActivity(Activity.class).create().visible().get();
|
|
mProvider = spy(new SearchFeatureProviderImpl());
|
|
}
|
|
|
|
@Test
|
|
public void getSiteMapManager_shouldCacheInstance() {
|
|
final SiteMapManager manager1 = mProvider.getSiteMapManager();
|
|
final SiteMapManager manager2 = mProvider.getSiteMapManager();
|
|
|
|
assertThat(manager1).isSameAs(manager2);
|
|
}
|
|
|
|
@Test
|
|
public void getDatabaseSearchLoader_shouldCleanupQuery() {
|
|
final String query = " space ";
|
|
|
|
mProvider.getStaticSearchResultTask(mActivity, query);
|
|
|
|
verify(mProvider).cleanQuery(eq(query));
|
|
}
|
|
|
|
@Test
|
|
public void getInstalledAppSearchLoader_shouldCleanupQuery() {
|
|
final String query = " space ";
|
|
|
|
mProvider.getInstalledAppSearchTask(mActivity, query);
|
|
|
|
verify(mProvider).cleanQuery(eq(query));
|
|
}
|
|
|
|
@Test(expected = IllegalArgumentException.class)
|
|
public void verifyLaunchSearchResultPageCaller_nullCaller_shouldCrash() {
|
|
mProvider.verifyLaunchSearchResultPageCaller(mActivity, null /* caller */);
|
|
}
|
|
|
|
@Test(expected = SecurityException.class)
|
|
public void everifyLaunchSearchResultPageCaller_badCaller_shouldCrash() {
|
|
final ComponentName cn = new ComponentName("pkg", "class");
|
|
mProvider.verifyLaunchSearchResultPageCaller(mActivity, cn);
|
|
}
|
|
|
|
@Test
|
|
public void verifyLaunchSearchResultPageCaller_goodCaller_shouldNotCrash() {
|
|
final ComponentName cn = new ComponentName(mActivity.getPackageName(), "class");
|
|
mProvider.verifyLaunchSearchResultPageCaller(mActivity, cn);
|
|
}
|
|
|
|
@Test
|
|
public void cleanQuery_trimsWhitespace() {
|
|
final String query = " space ";
|
|
final String cleanQuery = "space";
|
|
|
|
assertThat(mProvider.cleanQuery(query)).isEqualTo(cleanQuery);
|
|
}
|
|
}
|