Merge "Skip indexing dynamic and injected raw data when page search is disabled" into sc-dev
diff --git a/src/com/android/settings/search/BaseSearchIndexProvider.java b/src/com/android/settings/search/BaseSearchIndexProvider.java
index 3c2df96..581eb2e 100644
--- a/src/com/android/settings/search/BaseSearchIndexProvider.java
+++ b/src/com/android/settings/search/BaseSearchIndexProvider.java
@@ -80,6 +80,10 @@
@CallSuper
public List<SearchIndexableRaw> getDynamicRawDataToIndex(Context context, boolean enabled) {
final List<SearchIndexableRaw> dynamicRaws = new ArrayList<>();
+ if (!isPageSearchEnabled(context)) {
+ // Entire page should be suppressed, do not add dynamic raw data.
+ return dynamicRaws;
+ }
final List<AbstractPreferenceController> controllers = getPreferenceControllers(context);
if (controllers == null || controllers.isEmpty()) {
return dynamicRaws;
diff --git a/src/com/android/settings/search/SettingsSearchIndexablesProvider.java b/src/com/android/settings/search/SettingsSearchIndexablesProvider.java
index 736a270..feb9510 100644
--- a/src/com/android/settings/search/SettingsSearchIndexablesProvider.java
+++ b/src/com/android/settings/search/SettingsSearchIndexablesProvider.java
@@ -55,20 +55,22 @@
import android.provider.SearchIndexablesProvider;
import android.provider.SettingsSlicesContract;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import androidx.slice.SliceViewManager;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
+import com.android.settings.dashboard.CategoryManager;
import com.android.settings.dashboard.DashboardFeatureProvider;
+import com.android.settings.dashboard.DashboardFragmentRegistry;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.slices.SettingsSliceProvider;
import com.android.settingslib.drawer.ActivityTile;
-import com.android.settingslib.drawer.CategoryKey;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.Tile;
import com.android.settingslib.search.Indexable;
@@ -78,6 +80,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider {
@@ -94,6 +97,9 @@
private static final Collection<String> INVALID_KEYS;
+ // Search enabled states for injection (key: category key, value: search enabled)
+ private Map<String, Boolean> mSearchEnabledByCategoryKeyMap;
+
static {
INVALID_KEYS = new ArraySet<>();
INVALID_KEYS.add(null);
@@ -102,6 +108,7 @@
@Override
public boolean onCreate() {
+ mSearchEnabledByCategoryKeyMap = new ArrayMap<>();
return true;
}
@@ -166,7 +173,18 @@
public Cursor queryDynamicRawData(String[] projection) {
final Context context = getContext();
final List<SearchIndexableRaw> rawList = new ArrayList<>();
- rawList.addAll(getDynamicSearchIndexableRawFromProvider(context));
+ final Collection<SearchIndexableData> bundles = FeatureFactory.getFactory(context)
+ .getSearchFeatureProvider().getSearchIndexableResources().getProviderValues();
+
+ for (SearchIndexableData bundle : bundles) {
+ rawList.addAll(getDynamicSearchIndexableRawData(context, bundle));
+
+ // Refresh the search enabled state for indexing injection raw data
+ final Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider();
+ if (provider instanceof BaseSearchIndexProvider) {
+ refreshSearchEnabledState(context, (BaseSearchIndexProvider) provider);
+ }
+ }
rawList.addAll(getInjectionIndexableRawData(context));
final MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS);
@@ -355,39 +373,35 @@
return rawList;
}
- private List<SearchIndexableRaw> getDynamicSearchIndexableRawFromProvider(Context context) {
- final Collection<SearchIndexableData> bundles = FeatureFactory.getFactory(context)
- .getSearchFeatureProvider().getSearchIndexableResources().getProviderValues();
- final List<SearchIndexableRaw> rawList = new ArrayList<>();
-
- for (SearchIndexableData bundle : bundles) {
- final Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider();
- final List<SearchIndexableRaw> providerRaws =
- provider.getDynamicRawDataToIndex(context, true /* enabled */);
-
- if (providerRaws == null) {
- continue;
- }
-
- for (SearchIndexableRaw raw : providerRaws) {
- // The classname and intent information comes from the PreIndexData
- // This will be more clear when provider conversion is done at PreIndex time.
- raw.className = bundle.getTargetClass().getName();
-
- }
- rawList.addAll(providerRaws);
+ private List<SearchIndexableRaw> getDynamicSearchIndexableRawData(Context context,
+ SearchIndexableData bundle) {
+ final Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider();
+ final List<SearchIndexableRaw> providerRaws =
+ provider.getDynamicRawDataToIndex(context, true /* enabled */);
+ if (providerRaws == null) {
+ return new ArrayList<>();
}
- return rawList;
+ for (SearchIndexableRaw raw : providerRaws) {
+ // The classname and intent information comes from the PreIndexData
+ // This will be more clear when provider conversion is done at PreIndex time.
+ raw.className = bundle.getTargetClass().getName();
+ }
+ return providerRaws;
}
- private List<SearchIndexableRaw> getInjectionIndexableRawData(Context context) {
+ @VisibleForTesting
+ List<SearchIndexableRaw> getInjectionIndexableRawData(Context context) {
final DashboardFeatureProvider dashboardFeatureProvider =
FeatureFactory.getFactory(context).getDashboardFeatureProvider(context);
-
final List<SearchIndexableRaw> rawList = new ArrayList<>();
final String currentPackageName = context.getPackageName();
for (DashboardCategory category : dashboardFeatureProvider.getAllCategories()) {
+ if (mSearchEnabledByCategoryKeyMap.containsKey(category.key)
+ && !mSearchEnabledByCategoryKeyMap.get(category.key)) {
+ Log.i(TAG, "Skip indexing category: " + category.key);
+ continue;
+ }
for (Tile tile : category.getTiles()) {
if (!isEligibleForIndexing(currentPackageName, tile)) {
continue;
@@ -411,16 +425,36 @@
}
@VisibleForTesting
+ void refreshSearchEnabledState(Context context, BaseSearchIndexProvider provider) {
+ // Provider's class name is like "com.android.settings.Settings$1"
+ String className = provider.getClass().getName();
+ final int delimiter = className.lastIndexOf("$");
+ if (delimiter > 0) {
+ // Parse the outer class name of this provider
+ className = className.substring(0, delimiter);
+ }
+
+ // Lookup the category key by the class name
+ final String categoryKey = DashboardFragmentRegistry.PARENT_TO_CATEGORY_KEY_MAP
+ .get(className);
+ if (categoryKey == null) {
+ return;
+ }
+
+ final DashboardCategory category = CategoryManager.get(context)
+ .getTilesByCategory(context, categoryKey);
+ if (category != null) {
+ mSearchEnabledByCategoryKeyMap.put(category.key, provider.isPageSearchEnabled(context));
+ }
+ }
+
+ @VisibleForTesting
boolean isEligibleForIndexing(String packageName, Tile tile) {
if (TextUtils.equals(packageName, tile.getPackageName())
&& tile instanceof ActivityTile) {
// Skip Settings injected items because they should be indexed in the sub-pages.
return false;
}
- if (TextUtils.equals(tile.getCategory(), CategoryKey.CATEGORY_HOMEPAGE)) {
- // Skip homepage injected items since we would like to index their target activity.
- return false;
- }
return true;
}
diff --git a/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java b/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java
index 5221630..09b1ea9 100644
--- a/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java
+++ b/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java
@@ -204,6 +204,16 @@
}
@Test
+ public void getDynamicRawDataToIndex_disablePageSearch_shouldReturnEmptyList() {
+ List<AbstractPreferenceController> controllers = new ArrayList<>();
+ controllers.add(new AvailablePreferenceController(mContext));
+ doReturn(controllers).when(mIndexProvider).createPreferenceControllers(mContext);
+ doReturn(false).when(mIndexProvider).isPageSearchEnabled(mContext);
+
+ assertThat(mIndexProvider.getDynamicRawDataToIndex(mContext, true)).isEmpty();
+ }
+
+ @Test
public void getDynamicRawDataToIndex_hasDynamicRaw_shouldNotEmpty() {
List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new AvailablePreferenceController(mContext));
diff --git a/tests/robotests/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java b/tests/robotests/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java
index 1fc0230..21b00a3 100644
--- a/tests/robotests/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java
+++ b/tests/robotests/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java
@@ -1,21 +1,31 @@
package com.android.settings.search;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
import android.Manifest;
+import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Bundle;
import android.provider.SearchIndexablesContract;
import com.android.settings.R;
+import com.android.settings.accounts.ManagedProfileSettings;
+import com.android.settings.dashboard.CategoryManager;
+import com.android.settings.homepage.TopLevelSettings;
+import com.android.settings.network.NetworkDashboardFragment;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.drawer.ActivityTile;
import com.android.settingslib.drawer.CategoryKey;
+import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.search.SearchIndexableData;
import org.junit.After;
@@ -25,21 +35,28 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = SettingsSearchIndexablesProviderTest.ShadowCategoryManager.class)
public class SettingsSearchIndexablesProviderTest {
private static final String PACKAGE_NAME = "com.android.settings";
private static final String BASE_AUTHORITY = "content://" + PACKAGE_NAME + "/";
+ private Context mContext;
private SettingsSearchIndexablesProvider mProvider;
private FakeFeatureFactory mFakeFeatureFactory;
@Before
public void setUp() {
+ mContext = RuntimeEnvironment.application;
mProvider = spy(new SettingsSearchIndexablesProvider());
ProviderInfo info = new ProviderInfo();
info.exported = true;
@@ -55,10 +72,22 @@
FakeSettingsFragment.SEARCH_INDEX_DATA_PROVIDER));
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mFakeFeatureFactory.searchFeatureProvider = featureProvider;
+
+ final ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.packageName = "pkg";
+ activityInfo.name = "class";
+ activityInfo.metaData = new Bundle();
+ activityInfo.metaData.putString(META_DATA_PREFERENCE_TITLE, "title");
+ final DashboardCategory category = new DashboardCategory("key");
+ when(mFakeFeatureFactory.dashboardFeatureProvider.getAllCategories())
+ .thenReturn(Arrays.asList(category));
+ category.addTile(new ActivityTile(activityInfo, category.key));
+ ShadowCategoryManager.setDashboardCategory(category);
}
@After
public void cleanUp() {
+ ShadowCategoryManager.reset();
mFakeFeatureFactory.searchFeatureProvider = mock(SearchFeatureProvider.class);
}
@@ -121,7 +150,41 @@
}
@Test
- public void testIsEligibleForIndexing_isSettingsInjectedItem_ShouldBeFalse() {
+ public void refreshSearchEnabledState_classNotFoundInCategoryMap_hasInjectionRawData() {
+ mProvider.refreshSearchEnabledState(mContext,
+ ManagedProfileSettings.SEARCH_INDEX_DATA_PROVIDER);
+
+ assertThat(mProvider.getInjectionIndexableRawData(mContext)).isNotEmpty();
+ }
+
+ @Test
+ public void refreshSearchEnabledState_noDashboardCategory_hasInjectionRawData() {
+ ShadowCategoryManager.setDashboardCategory(null);
+
+ mProvider.refreshSearchEnabledState(mContext,
+ TopLevelSettings.SEARCH_INDEX_DATA_PROVIDER);
+
+ assertThat(mProvider.getInjectionIndexableRawData(mContext)).isNotEmpty();
+ }
+
+ @Test
+ public void refreshSearchEnabledState_pageSearchEnabled_hasInjectionRawData() {
+ mProvider.refreshSearchEnabledState(mContext,
+ NetworkDashboardFragment.SEARCH_INDEX_DATA_PROVIDER);
+
+ assertThat(mProvider.getInjectionIndexableRawData(mContext)).isNotEmpty();
+ }
+
+ @Test
+ public void refreshSearchEnabledState_pageSearchDisable_noInjectionRawData() {
+ mProvider.refreshSearchEnabledState(mContext,
+ TopLevelSettings.SEARCH_INDEX_DATA_PROVIDER);
+
+ assertThat(mProvider.getInjectionIndexableRawData(mContext)).isEmpty();
+ }
+
+ @Test
+ public void isEligibleForIndexing_isSettingsInjectedItem_shouldReturnFalse() {
final ActivityInfo activityInfo = new ActivityInfo();
activityInfo.packageName = PACKAGE_NAME;
activityInfo.name = "class";
@@ -132,18 +195,7 @@
}
@Test
- public void testIsEligibleForIndexing_isHomepageInjectedItem_ShouldBeFalse() {
- final ActivityInfo activityInfo = new ActivityInfo();
- activityInfo.packageName = "pkg";
- activityInfo.name = "class";
- final ActivityTile activityTile = new ActivityTile(activityInfo,
- CategoryKey.CATEGORY_HOMEPAGE);
-
- assertThat(mProvider.isEligibleForIndexing(PACKAGE_NAME, activityTile)).isFalse();
- }
-
- @Test
- public void testIsEligibleForIndexing_normalInjectedItem_ShouldBeTrue() {
+ public void isEligibleForIndexing_normalInjectedItem_shouldReturnTrue() {
final ActivityInfo activityInfo = new ActivityInfo();
activityInfo.packageName = "pkg";
activityInfo.name = "class";
@@ -152,4 +204,24 @@
assertThat(mProvider.isEligibleForIndexing(PACKAGE_NAME, activityTile)).isTrue();
}
+
+ @Implements(CategoryManager.class)
+ public static class ShadowCategoryManager {
+
+ private static DashboardCategory sCategory;
+
+ @Resetter
+ static void reset() {
+ sCategory = null;
+ }
+
+ @Implementation
+ public DashboardCategory getTilesByCategory(Context context, String categoryKey) {
+ return sCategory;
+ }
+
+ static void setDashboardCategory(DashboardCategory category) {
+ sCategory = category;
+ }
+ }
}