Loading src/com/android/settings/search/BaseSearchIndexProvider.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -80,6 +80,10 @@ public class BaseSearchIndexProvider implements Indexable.SearchIndexProvider { @CallSuper @CallSuper public List<SearchIndexableRaw> getDynamicRawDataToIndex(Context context, boolean enabled) { public List<SearchIndexableRaw> getDynamicRawDataToIndex(Context context, boolean enabled) { final List<SearchIndexableRaw> dynamicRaws = new ArrayList<>(); 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); final List<AbstractPreferenceController> controllers = getPreferenceControllers(context); if (controllers == null || controllers.isEmpty()) { if (controllers == null || controllers.isEmpty()) { return dynamicRaws; return dynamicRaws; Loading src/com/android/settings/search/SettingsSearchIndexablesProvider.java +65 −31 Original line number Original line Diff line number Diff line Loading @@ -55,20 +55,22 @@ import android.provider.SearchIndexablesContract; import android.provider.SearchIndexablesProvider; import android.provider.SearchIndexablesProvider; import android.provider.SettingsSlicesContract; import android.provider.SettingsSlicesContract; import android.text.TextUtils; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.ArraySet; import android.util.Log; import android.util.Log; import androidx.annotation.Nullable; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.slice.SliceViewManager; import androidx.slice.SliceViewManager; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity; import com.android.settings.dashboard.CategoryManager; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.DashboardFragmentRegistry; import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory; import com.android.settings.slices.SettingsSliceProvider; import com.android.settings.slices.SettingsSliceProvider; import com.android.settingslib.drawer.ActivityTile; import com.android.settingslib.drawer.ActivityTile; import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.Tile; import com.android.settingslib.drawer.Tile; import com.android.settingslib.search.Indexable; import com.android.settingslib.search.Indexable; Loading @@ -78,6 +80,7 @@ import com.android.settingslib.search.SearchIndexableRaw; import java.util.ArrayList; import java.util.ArrayList; import java.util.Collection; import java.util.Collection; import java.util.List; import java.util.List; import java.util.Map; public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { Loading @@ -94,6 +97,9 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { private static final Collection<String> INVALID_KEYS; private static final Collection<String> INVALID_KEYS; // Search enabled states for injection (key: category key, value: search enabled) private Map<String, Boolean> mSearchEnabledByCategoryKeyMap; static { static { INVALID_KEYS = new ArraySet<>(); INVALID_KEYS = new ArraySet<>(); INVALID_KEYS.add(null); INVALID_KEYS.add(null); Loading @@ -102,6 +108,7 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { @Override @Override public boolean onCreate() { public boolean onCreate() { mSearchEnabledByCategoryKeyMap = new ArrayMap<>(); return true; return true; } } Loading Loading @@ -166,7 +173,18 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { public Cursor queryDynamicRawData(String[] projection) { public Cursor queryDynamicRawData(String[] projection) { final Context context = getContext(); final Context context = getContext(); final List<SearchIndexableRaw> rawList = new ArrayList<>(); 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)); rawList.addAll(getInjectionIndexableRawData(context)); final MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS); final MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS); Loading Loading @@ -355,39 +373,35 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { return rawList; return rawList; } } private List<SearchIndexableRaw> getDynamicSearchIndexableRawFromProvider(Context context) { private List<SearchIndexableRaw> getDynamicSearchIndexableRawData(Context context, final Collection<SearchIndexableData> bundles = FeatureFactory.getFactory(context) SearchIndexableData bundle) { .getSearchFeatureProvider().getSearchIndexableResources().getProviderValues(); final List<SearchIndexableRaw> rawList = new ArrayList<>(); for (SearchIndexableData bundle : bundles) { final Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider(); final Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider(); final List<SearchIndexableRaw> providerRaws = final List<SearchIndexableRaw> providerRaws = provider.getDynamicRawDataToIndex(context, true /* enabled */); provider.getDynamicRawDataToIndex(context, true /* enabled */); if (providerRaws == null) { if (providerRaws == null) { continue; return new ArrayList<>(); } } for (SearchIndexableRaw raw : providerRaws) { for (SearchIndexableRaw raw : providerRaws) { // The classname and intent information comes from the PreIndexData // The classname and intent information comes from the PreIndexData // This will be more clear when provider conversion is done at PreIndex time. // This will be more clear when provider conversion is done at PreIndex time. raw.className = bundle.getTargetClass().getName(); raw.className = bundle.getTargetClass().getName(); } } rawList.addAll(providerRaws); return providerRaws; } } return rawList; @VisibleForTesting } List<SearchIndexableRaw> getInjectionIndexableRawData(Context context) { private List<SearchIndexableRaw> getInjectionIndexableRawData(Context context) { final DashboardFeatureProvider dashboardFeatureProvider = final DashboardFeatureProvider dashboardFeatureProvider = FeatureFactory.getFactory(context).getDashboardFeatureProvider(context); FeatureFactory.getFactory(context).getDashboardFeatureProvider(context); final List<SearchIndexableRaw> rawList = new ArrayList<>(); final List<SearchIndexableRaw> rawList = new ArrayList<>(); final String currentPackageName = context.getPackageName(); final String currentPackageName = context.getPackageName(); for (DashboardCategory category : dashboardFeatureProvider.getAllCategories()) { 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()) { for (Tile tile : category.getTiles()) { if (!isEligibleForIndexing(currentPackageName, tile)) { if (!isEligibleForIndexing(currentPackageName, tile)) { continue; continue; Loading @@ -410,6 +424,30 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { return rawList; return rawList; } } @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 @VisibleForTesting boolean isEligibleForIndexing(String packageName, Tile tile) { boolean isEligibleForIndexing(String packageName, Tile tile) { if (TextUtils.equals(packageName, tile.getPackageName()) if (TextUtils.equals(packageName, tile.getPackageName()) Loading @@ -417,10 +455,6 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { // Skip Settings injected items because they should be indexed in the sub-pages. // Skip Settings injected items because they should be indexed in the sub-pages. return false; 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; return true; } } Loading tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java +10 −0 Original line number Original line Diff line number Diff line Loading @@ -203,6 +203,16 @@ public class BaseSearchIndexProviderTest { assertThat(mIndexProvider.getDynamicRawDataToIndex(mContext, true)).isEmpty(); assertThat(mIndexProvider.getDynamicRawDataToIndex(mContext, true)).isEmpty(); } } @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 @Test public void getDynamicRawDataToIndex_hasDynamicRaw_shouldNotEmpty() { public void getDynamicRawDataToIndex_hasDynamicRaw_shouldNotEmpty() { List<AbstractPreferenceController> controllers = new ArrayList<>(); List<AbstractPreferenceController> controllers = new ArrayList<>(); Loading tests/robotests/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java +83 −11 Original line number Original line Diff line number Diff line package com.android.settings.search; 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 com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.Manifest; import android.Manifest; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo; import android.content.pm.ProviderInfo; import android.content.pm.ProviderInfo; import android.database.Cursor; import android.database.Cursor; import android.net.Uri; import android.net.Uri; import android.os.Bundle; import android.provider.SearchIndexablesContract; import android.provider.SearchIndexablesContract; import com.android.settings.R; 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.settings.testutils.FakeFeatureFactory; import com.android.settingslib.drawer.ActivityTile; import com.android.settingslib.drawer.ActivityTile; import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.search.SearchIndexableData; import com.android.settingslib.search.SearchIndexableData; import org.junit.After; import org.junit.After; Loading @@ -25,21 +35,28 @@ import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; 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.ArrayList; import java.util.Arrays; import java.util.List; import java.util.List; @RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class) @Config(shadows = SettingsSearchIndexablesProviderTest.ShadowCategoryManager.class) public class SettingsSearchIndexablesProviderTest { public class SettingsSearchIndexablesProviderTest { private static final String PACKAGE_NAME = "com.android.settings"; private static final String PACKAGE_NAME = "com.android.settings"; private static final String BASE_AUTHORITY = "content://" + PACKAGE_NAME + "/"; private static final String BASE_AUTHORITY = "content://" + PACKAGE_NAME + "/"; private Context mContext; private SettingsSearchIndexablesProvider mProvider; private SettingsSearchIndexablesProvider mProvider; private FakeFeatureFactory mFakeFeatureFactory; private FakeFeatureFactory mFakeFeatureFactory; @Before @Before public void setUp() { public void setUp() { mContext = RuntimeEnvironment.application; mProvider = spy(new SettingsSearchIndexablesProvider()); mProvider = spy(new SettingsSearchIndexablesProvider()); ProviderInfo info = new ProviderInfo(); ProviderInfo info = new ProviderInfo(); info.exported = true; info.exported = true; Loading @@ -55,10 +72,22 @@ public class SettingsSearchIndexablesProviderTest { FakeSettingsFragment.SEARCH_INDEX_DATA_PROVIDER)); FakeSettingsFragment.SEARCH_INDEX_DATA_PROVIDER)); mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); mFakeFeatureFactory.searchFeatureProvider = featureProvider; 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 @After public void cleanUp() { public void cleanUp() { ShadowCategoryManager.reset(); mFakeFeatureFactory.searchFeatureProvider = mock(SearchFeatureProvider.class); mFakeFeatureFactory.searchFeatureProvider = mock(SearchFeatureProvider.class); } } Loading Loading @@ -121,29 +150,52 @@ public class SettingsSearchIndexablesProviderTest { } } @Test @Test public void testIsEligibleForIndexing_isSettingsInjectedItem_ShouldBeFalse() { public void refreshSearchEnabledState_classNotFoundInCategoryMap_hasInjectionRawData() { final ActivityInfo activityInfo = new ActivityInfo(); mProvider.refreshSearchEnabledState(mContext, activityInfo.packageName = PACKAGE_NAME; ManagedProfileSettings.SEARCH_INDEX_DATA_PROVIDER); activityInfo.name = "class"; final ActivityTile activityTile = new ActivityTile(activityInfo, CategoryKey.CATEGORY_SYSTEM); assertThat(mProvider.isEligibleForIndexing(PACKAGE_NAME, activityTile)).isFalse(); 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 @Test public void testIsEligibleForIndexing_isHomepageInjectedItem_ShouldBeFalse() { 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(); final ActivityInfo activityInfo = new ActivityInfo(); activityInfo.packageName = "pkg"; activityInfo.packageName = PACKAGE_NAME; activityInfo.name = "class"; activityInfo.name = "class"; final ActivityTile activityTile = new ActivityTile(activityInfo, final ActivityTile activityTile = new ActivityTile(activityInfo, CategoryKey.CATEGORY_HOMEPAGE); CategoryKey.CATEGORY_SYSTEM); assertThat(mProvider.isEligibleForIndexing(PACKAGE_NAME, activityTile)).isFalse(); assertThat(mProvider.isEligibleForIndexing(PACKAGE_NAME, activityTile)).isFalse(); } } @Test @Test public void testIsEligibleForIndexing_normalInjectedItem_ShouldBeTrue() { public void isEligibleForIndexing_normalInjectedItem_shouldReturnTrue() { final ActivityInfo activityInfo = new ActivityInfo(); final ActivityInfo activityInfo = new ActivityInfo(); activityInfo.packageName = "pkg"; activityInfo.packageName = "pkg"; activityInfo.name = "class"; activityInfo.name = "class"; Loading @@ -152,4 +204,24 @@ public class SettingsSearchIndexablesProviderTest { assertThat(mProvider.isEligibleForIndexing(PACKAGE_NAME, activityTile)).isTrue(); 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; } } } } Loading
src/com/android/settings/search/BaseSearchIndexProvider.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -80,6 +80,10 @@ public class BaseSearchIndexProvider implements Indexable.SearchIndexProvider { @CallSuper @CallSuper public List<SearchIndexableRaw> getDynamicRawDataToIndex(Context context, boolean enabled) { public List<SearchIndexableRaw> getDynamicRawDataToIndex(Context context, boolean enabled) { final List<SearchIndexableRaw> dynamicRaws = new ArrayList<>(); 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); final List<AbstractPreferenceController> controllers = getPreferenceControllers(context); if (controllers == null || controllers.isEmpty()) { if (controllers == null || controllers.isEmpty()) { return dynamicRaws; return dynamicRaws; Loading
src/com/android/settings/search/SettingsSearchIndexablesProvider.java +65 −31 Original line number Original line Diff line number Diff line Loading @@ -55,20 +55,22 @@ import android.provider.SearchIndexablesContract; import android.provider.SearchIndexablesProvider; import android.provider.SearchIndexablesProvider; import android.provider.SettingsSlicesContract; import android.provider.SettingsSlicesContract; import android.text.TextUtils; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.ArraySet; import android.util.Log; import android.util.Log; import androidx.annotation.Nullable; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.slice.SliceViewManager; import androidx.slice.SliceViewManager; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity; import com.android.settings.dashboard.CategoryManager; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.DashboardFragmentRegistry; import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory; import com.android.settings.slices.SettingsSliceProvider; import com.android.settings.slices.SettingsSliceProvider; import com.android.settingslib.drawer.ActivityTile; import com.android.settingslib.drawer.ActivityTile; import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.Tile; import com.android.settingslib.drawer.Tile; import com.android.settingslib.search.Indexable; import com.android.settingslib.search.Indexable; Loading @@ -78,6 +80,7 @@ import com.android.settingslib.search.SearchIndexableRaw; import java.util.ArrayList; import java.util.ArrayList; import java.util.Collection; import java.util.Collection; import java.util.List; import java.util.List; import java.util.Map; public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { Loading @@ -94,6 +97,9 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { private static final Collection<String> INVALID_KEYS; private static final Collection<String> INVALID_KEYS; // Search enabled states for injection (key: category key, value: search enabled) private Map<String, Boolean> mSearchEnabledByCategoryKeyMap; static { static { INVALID_KEYS = new ArraySet<>(); INVALID_KEYS = new ArraySet<>(); INVALID_KEYS.add(null); INVALID_KEYS.add(null); Loading @@ -102,6 +108,7 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { @Override @Override public boolean onCreate() { public boolean onCreate() { mSearchEnabledByCategoryKeyMap = new ArrayMap<>(); return true; return true; } } Loading Loading @@ -166,7 +173,18 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { public Cursor queryDynamicRawData(String[] projection) { public Cursor queryDynamicRawData(String[] projection) { final Context context = getContext(); final Context context = getContext(); final List<SearchIndexableRaw> rawList = new ArrayList<>(); 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)); rawList.addAll(getInjectionIndexableRawData(context)); final MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS); final MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS); Loading Loading @@ -355,39 +373,35 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { return rawList; return rawList; } } private List<SearchIndexableRaw> getDynamicSearchIndexableRawFromProvider(Context context) { private List<SearchIndexableRaw> getDynamicSearchIndexableRawData(Context context, final Collection<SearchIndexableData> bundles = FeatureFactory.getFactory(context) SearchIndexableData bundle) { .getSearchFeatureProvider().getSearchIndexableResources().getProviderValues(); final List<SearchIndexableRaw> rawList = new ArrayList<>(); for (SearchIndexableData bundle : bundles) { final Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider(); final Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider(); final List<SearchIndexableRaw> providerRaws = final List<SearchIndexableRaw> providerRaws = provider.getDynamicRawDataToIndex(context, true /* enabled */); provider.getDynamicRawDataToIndex(context, true /* enabled */); if (providerRaws == null) { if (providerRaws == null) { continue; return new ArrayList<>(); } } for (SearchIndexableRaw raw : providerRaws) { for (SearchIndexableRaw raw : providerRaws) { // The classname and intent information comes from the PreIndexData // The classname and intent information comes from the PreIndexData // This will be more clear when provider conversion is done at PreIndex time. // This will be more clear when provider conversion is done at PreIndex time. raw.className = bundle.getTargetClass().getName(); raw.className = bundle.getTargetClass().getName(); } } rawList.addAll(providerRaws); return providerRaws; } } return rawList; @VisibleForTesting } List<SearchIndexableRaw> getInjectionIndexableRawData(Context context) { private List<SearchIndexableRaw> getInjectionIndexableRawData(Context context) { final DashboardFeatureProvider dashboardFeatureProvider = final DashboardFeatureProvider dashboardFeatureProvider = FeatureFactory.getFactory(context).getDashboardFeatureProvider(context); FeatureFactory.getFactory(context).getDashboardFeatureProvider(context); final List<SearchIndexableRaw> rawList = new ArrayList<>(); final List<SearchIndexableRaw> rawList = new ArrayList<>(); final String currentPackageName = context.getPackageName(); final String currentPackageName = context.getPackageName(); for (DashboardCategory category : dashboardFeatureProvider.getAllCategories()) { 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()) { for (Tile tile : category.getTiles()) { if (!isEligibleForIndexing(currentPackageName, tile)) { if (!isEligibleForIndexing(currentPackageName, tile)) { continue; continue; Loading @@ -410,6 +424,30 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { return rawList; return rawList; } } @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 @VisibleForTesting boolean isEligibleForIndexing(String packageName, Tile tile) { boolean isEligibleForIndexing(String packageName, Tile tile) { if (TextUtils.equals(packageName, tile.getPackageName()) if (TextUtils.equals(packageName, tile.getPackageName()) Loading @@ -417,10 +455,6 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { // Skip Settings injected items because they should be indexed in the sub-pages. // Skip Settings injected items because they should be indexed in the sub-pages. return false; 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; return true; } } Loading
tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java +10 −0 Original line number Original line Diff line number Diff line Loading @@ -203,6 +203,16 @@ public class BaseSearchIndexProviderTest { assertThat(mIndexProvider.getDynamicRawDataToIndex(mContext, true)).isEmpty(); assertThat(mIndexProvider.getDynamicRawDataToIndex(mContext, true)).isEmpty(); } } @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 @Test public void getDynamicRawDataToIndex_hasDynamicRaw_shouldNotEmpty() { public void getDynamicRawDataToIndex_hasDynamicRaw_shouldNotEmpty() { List<AbstractPreferenceController> controllers = new ArrayList<>(); List<AbstractPreferenceController> controllers = new ArrayList<>(); Loading
tests/robotests/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java +83 −11 Original line number Original line Diff line number Diff line package com.android.settings.search; 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 com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.Manifest; import android.Manifest; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo; import android.content.pm.ProviderInfo; import android.content.pm.ProviderInfo; import android.database.Cursor; import android.database.Cursor; import android.net.Uri; import android.net.Uri; import android.os.Bundle; import android.provider.SearchIndexablesContract; import android.provider.SearchIndexablesContract; import com.android.settings.R; 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.settings.testutils.FakeFeatureFactory; import com.android.settingslib.drawer.ActivityTile; import com.android.settingslib.drawer.ActivityTile; import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.search.SearchIndexableData; import com.android.settingslib.search.SearchIndexableData; import org.junit.After; import org.junit.After; Loading @@ -25,21 +35,28 @@ import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; 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.ArrayList; import java.util.Arrays; import java.util.List; import java.util.List; @RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class) @Config(shadows = SettingsSearchIndexablesProviderTest.ShadowCategoryManager.class) public class SettingsSearchIndexablesProviderTest { public class SettingsSearchIndexablesProviderTest { private static final String PACKAGE_NAME = "com.android.settings"; private static final String PACKAGE_NAME = "com.android.settings"; private static final String BASE_AUTHORITY = "content://" + PACKAGE_NAME + "/"; private static final String BASE_AUTHORITY = "content://" + PACKAGE_NAME + "/"; private Context mContext; private SettingsSearchIndexablesProvider mProvider; private SettingsSearchIndexablesProvider mProvider; private FakeFeatureFactory mFakeFeatureFactory; private FakeFeatureFactory mFakeFeatureFactory; @Before @Before public void setUp() { public void setUp() { mContext = RuntimeEnvironment.application; mProvider = spy(new SettingsSearchIndexablesProvider()); mProvider = spy(new SettingsSearchIndexablesProvider()); ProviderInfo info = new ProviderInfo(); ProviderInfo info = new ProviderInfo(); info.exported = true; info.exported = true; Loading @@ -55,10 +72,22 @@ public class SettingsSearchIndexablesProviderTest { FakeSettingsFragment.SEARCH_INDEX_DATA_PROVIDER)); FakeSettingsFragment.SEARCH_INDEX_DATA_PROVIDER)); mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); mFakeFeatureFactory.searchFeatureProvider = featureProvider; 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 @After public void cleanUp() { public void cleanUp() { ShadowCategoryManager.reset(); mFakeFeatureFactory.searchFeatureProvider = mock(SearchFeatureProvider.class); mFakeFeatureFactory.searchFeatureProvider = mock(SearchFeatureProvider.class); } } Loading Loading @@ -121,29 +150,52 @@ public class SettingsSearchIndexablesProviderTest { } } @Test @Test public void testIsEligibleForIndexing_isSettingsInjectedItem_ShouldBeFalse() { public void refreshSearchEnabledState_classNotFoundInCategoryMap_hasInjectionRawData() { final ActivityInfo activityInfo = new ActivityInfo(); mProvider.refreshSearchEnabledState(mContext, activityInfo.packageName = PACKAGE_NAME; ManagedProfileSettings.SEARCH_INDEX_DATA_PROVIDER); activityInfo.name = "class"; final ActivityTile activityTile = new ActivityTile(activityInfo, CategoryKey.CATEGORY_SYSTEM); assertThat(mProvider.isEligibleForIndexing(PACKAGE_NAME, activityTile)).isFalse(); 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 @Test public void testIsEligibleForIndexing_isHomepageInjectedItem_ShouldBeFalse() { 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(); final ActivityInfo activityInfo = new ActivityInfo(); activityInfo.packageName = "pkg"; activityInfo.packageName = PACKAGE_NAME; activityInfo.name = "class"; activityInfo.name = "class"; final ActivityTile activityTile = new ActivityTile(activityInfo, final ActivityTile activityTile = new ActivityTile(activityInfo, CategoryKey.CATEGORY_HOMEPAGE); CategoryKey.CATEGORY_SYSTEM); assertThat(mProvider.isEligibleForIndexing(PACKAGE_NAME, activityTile)).isFalse(); assertThat(mProvider.isEligibleForIndexing(PACKAGE_NAME, activityTile)).isFalse(); } } @Test @Test public void testIsEligibleForIndexing_normalInjectedItem_ShouldBeTrue() { public void isEligibleForIndexing_normalInjectedItem_shouldReturnTrue() { final ActivityInfo activityInfo = new ActivityInfo(); final ActivityInfo activityInfo = new ActivityInfo(); activityInfo.packageName = "pkg"; activityInfo.packageName = "pkg"; activityInfo.name = "class"; activityInfo.name = "class"; Loading @@ -152,4 +204,24 @@ public class SettingsSearchIndexablesProviderTest { assertThat(mProvider.isEligibleForIndexing(PACKAGE_NAME, activityTile)).isTrue(); 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; } } } }