Integrated SearchIndexableResources interface in Settings

- New SearchIndexableResources interface returns SearchIndexableBundle,
we don't need reflection to get SearchIndexableProvider

Bug: 135053028
Test: robolectric, check database search_index.db items
Change-Id: I5ed3416ccf72ef3d38db817fcb4aff7502649ed4
This commit is contained in:
Raff Tsai
2019-09-27 13:45:23 +08:00
parent cdaa57742e
commit c5e1fc677c
14 changed files with 109 additions and 105 deletions

View File

@@ -10,12 +10,11 @@ import android.util.AttributeSet;
import android.util.Xml;
import com.android.settings.R;
import com.android.settings.search.DatabaseIndexingUtils;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.search.SearchFeatureProviderImpl;
import com.android.settings.security.SecuritySettings;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.search.Indexable;
import com.android.settingslib.search.SearchIndexableData;
import org.junit.Before;
import org.junit.Test;
@@ -35,9 +34,6 @@ import java.util.Set;
@RunWith(RobolectricTestRunner.class)
public class XmlControllerAttributeTest {
// List of classes that are too hard to mock in order to retrieve xml information.
private final List<Class> illegalClasses = Arrays.asList(SecuritySettings.class);
// List of XML that could be retrieved from the illegalClasses list.
private final List<Integer> whitelistXml = Arrays.asList(R.xml.security_dashboard_settings);
@@ -112,14 +108,12 @@ public class XmlControllerAttributeTest {
private Set<Integer> getIndexableXml() {
Set<Integer> xmlResSet = new HashSet<>();
Collection<Class> indexableClasses =
Collection<SearchIndexableData> SearchIndexableDatas =
mSearchProvider.getSearchIndexableResources().getProviderValues();
indexableClasses.removeAll(illegalClasses);
for (Class clazz : indexableClasses) {
for (SearchIndexableData bundle : SearchIndexableDatas) {
Indexable.SearchIndexProvider provider =
DatabaseIndexingUtils.getSearchIndexProvider(clazz);
Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider();
if (provider == null) {
continue;

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2017 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 android.util.Log;
import com.android.settingslib.search.Indexable;
import java.lang.reflect.Field;
/**
* Utility class for {@like DatabaseIndexingManager} to handle the mapping between Payloads
* and Preference controllers, and managing indexable classes.
*/
public class DatabaseIndexingUtils {
private static final String TAG = "IndexingUtil";
public static final String FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER =
"SEARCH_INDEX_DATA_PROVIDER";
public static Indexable.SearchIndexProvider getSearchIndexProvider(final Class<?> clazz) {
try {
final Field f = clazz.getField(FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER);
return (Indexable.SearchIndexProvider) f.get(null);
} catch (NoSuchFieldException e) {
Log.d(TAG, "Cannot find field '" + FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'");
} catch (SecurityException se) {
Log.d(TAG,
"Security exception for field '" + FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'");
} catch (IllegalAccessException e) {
Log.d(TAG, "Illegal access to field '" + FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'");
} catch (IllegalArgumentException e) {
Log.d(TAG, "Illegal argument when accessing field '"
+ FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'");
}
return null;
}
}

View File

@@ -26,6 +26,7 @@ import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.core.codeinspection.CodeInspector;
import com.android.settings.dashboard.DashboardFragmentSearchIndexProviderInspector;
import com.android.settingslib.search.Indexable;
import com.android.settingslib.search.SearchIndexableData;
import com.android.settingslib.search.SearchIndexableResources;
import org.robolectric.RuntimeEnvironment;
@@ -54,7 +55,7 @@ public class SearchIndexProviderCodeInspector extends CodeInspector {
+ " but these are not: \n";
private static final String NOT_PROVIDING_VALID_RESOURCE_ERROR =
"SearchIndexableProvider must either provide no resource to index, or valid ones. "
+ "But the followings contain resource with xml id = 0\n";
+ "But the followings contain resource with xml id = 0\n";
private final List<String> notImplementingIndexProviderGrandfatherList;
private final List<String> notInSearchIndexableRegistryGrandfatherList;
@@ -79,6 +80,13 @@ public class SearchIndexProviderCodeInspector extends CodeInspector {
final Set<String> notInSearchProviderRegistry = new ArraySet<>();
final Set<String> notSharingPreferenceControllers = new ArraySet<>();
final Set<String> notProvidingValidResource = new ArraySet<>();
final Set<Class> providerClasses = new ArraySet<>();
final SearchFeatureProvider provider = new SearchFeatureProviderImpl();
for (SearchIndexableData bundle :
provider.getSearchIndexableResources().getProviderValues()) {
providerClasses.add(bundle.getTargetClass());
}
for (Class clazz : mClasses) {
if (!isConcreteSettingsClass(clazz)) {
@@ -108,8 +116,7 @@ public class SearchIndexProviderCodeInspector extends CodeInspector {
continue;
}
// Must be in SearchProviderRegistry
SearchFeatureProvider provider = new SearchFeatureProviderImpl();
if (!provider.getSearchIndexableResources().getProviderValues().contains(clazz)) {
if (!providerClasses.contains(clazz)) {
if (!notInSearchIndexableRegistryGrandfatherList.remove(className)) {
notInSearchProviderRegistry.add(className);
}

View File

@@ -21,7 +21,6 @@ import static android.provider.SearchIndexablesContract.COLUMN_INDEX_NON_INDEXAB
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -32,6 +31,7 @@ import android.text.TextUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.FakeIndexProvider;
import com.android.settings.wifi.WifiSettings;
import com.android.settingslib.search.SearchIndexableData;
import org.junit.After;
import org.junit.Before;
@@ -65,11 +65,11 @@ public class SearchIndexableResourcesTest {
.doesNotContain(String.class);
final int beforeCount =
mSearchProvider.getSearchIndexableResources().getProviderValues().size();
mSearchProvider.getSearchIndexableResources().addIndex(String.class);
final SearchIndexableData testBundle = new SearchIndexableData(null, null);
mSearchProvider.getSearchIndexableResources().addIndex(testBundle);
assertThat(mSearchProvider.getSearchIndexableResources().getProviderValues())
.contains(String.class);
.contains(testBundle);
final int afterCount =
mSearchProvider.getSearchIndexableResources().getProviderValues().size();
assertThat(afterCount).isEqualTo(beforeCount + 1);
@@ -77,14 +77,22 @@ public class SearchIndexableResourcesTest {
@Test
public void testIndexHasWifiSettings() {
assertThat(mSearchProvider.getSearchIndexableResources().getProviderValues())
.contains(WifiSettings.class);
boolean hasWifi = false;
for (SearchIndexableData bundle :
mSearchProvider.getSearchIndexableResources().getProviderValues()) {
if (bundle.getTargetClass().getName().equals(WifiSettings.class.getName())) {
hasWifi = true;
break;
}
}
assertThat(hasWifi).isTrue();
}
@Test
public void testNonIndexableKeys_GetsKeyFromProvider() {
mSearchProvider.getSearchIndexableResources().getProviderValues().clear();
mSearchProvider.getSearchIndexableResources().addIndex(FakeIndexProvider.class);
mSearchProvider.getSearchIndexableResources().addIndex(
new SearchIndexableData(null, FakeIndexProvider.SEARCH_INDEX_DATA_PROVIDER));
SettingsSearchIndexablesProvider provider = spy(new SettingsSearchIndexablesProvider());
@@ -105,9 +113,10 @@ public class SearchIndexableResourcesTest {
@Test
public void testAllClassNamesHaveProviders() {
for (Class clazz : mSearchProvider.getSearchIndexableResources().getProviderValues()) {
if (DatabaseIndexingUtils.getSearchIndexProvider(clazz) == null) {
fail(clazz.getName() + "is not an index provider");
for (SearchIndexableData data :
mSearchProvider.getSearchIndexableResources().getProviderValues()) {
if (DatabaseIndexingUtils.getSearchIndexProvider(data.getTargetClass()) == null) {
fail(data.getTargetClass().getName() + "is not an index provider");
}
}
}

View File

@@ -13,6 +13,7 @@ import android.provider.SearchIndexablesContract;
import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.search.SearchIndexableData;
import org.junit.After;
import org.junit.Before;
@@ -46,7 +47,8 @@ public class SettingsSearchIndexablesProviderTest {
final SearchFeatureProvider featureProvider = new SearchFeatureProviderImpl();
featureProvider.getSearchIndexableResources().getProviderValues().clear();
featureProvider.getSearchIndexableResources().getProviderValues()
.add(FakeSettingsFragment.class);
.add(new SearchIndexableData(FakeSettingsFragment.class,
FakeSettingsFragment.SEARCH_INDEX_DATA_PROVIDER));
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mFakeFeatureFactory.searchFeatureProvider = featureProvider;
}

View File

@@ -31,11 +31,11 @@ import com.android.settings.core.SliderPreferenceController;
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.core.codeinspection.CodeInspector;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.DatabaseIndexingUtils;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.search.SearchFeatureProviderImpl;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.search.Indexable;
import com.android.settingslib.search.SearchIndexableData;
import org.robolectric.RuntimeEnvironment;
import org.xmlpull.v1.XmlPullParserException;
@@ -146,13 +146,12 @@ public class SliceControllerInXmlCodeInspector extends CodeInspector {
private List<Integer> getIndexableXml() {
final List<Integer> xmlResSet = new ArrayList<>();
final Collection<Class> indexableClasses = FeatureFactory.getFactory(
final Collection<SearchIndexableData> bundles = FeatureFactory.getFactory(
mContext).getSearchFeatureProvider().getSearchIndexableResources()
.getProviderValues();
for (Class clazz : indexableClasses) {
Indexable.SearchIndexProvider provider = DatabaseIndexingUtils.getSearchIndexProvider(
clazz);
for (SearchIndexableData bundle : bundles) {
Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider();
if (provider == null) {
continue;

View File

@@ -37,6 +37,7 @@ import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.search.SearchFeatureProviderImpl;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.FakeIndexProvider;
import com.android.settingslib.search.SearchIndexableData;
import org.junit.After;
import org.junit.Before;
@@ -92,7 +93,8 @@ public class SliceDataConverterTest {
public void testFakeProvider_convertsFakeData() {
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues()
.add(FakeIndexProvider.class);
.add(new SearchIndexableData(FakeIndexProvider.class,
FakeIndexProvider.SEARCH_INDEX_DATA_PROVIDER));
doReturn(getFakeService()).when(mSliceDataConverter).getAccessibilityServiceInfoList();

View File

@@ -24,9 +24,7 @@ import static org.mockito.Mockito.spy;
import android.app.ApplicationPackageManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.provider.SettingsSlicesContract;
import android.view.accessibility.AccessibilityManager;
@@ -40,6 +38,7 @@ import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settingslib.search.SearchIndexableData;
import org.junit.After;
import org.junit.Before;
@@ -217,7 +216,8 @@ public class SlicesDatabaseAccessorTest {
// Fake the indexable list.
provider.getSearchIndexableResources().getProviderValues().clear();
provider.getSearchIndexableResources().getProviderValues().add(
FakeIndexProvider.class);
new SearchIndexableData(FakeIndexProvider.class,
FakeIndexProvider.SEARCH_INDEX_DATA_PROVIDER));
final SlicesDatabaseAccessor accessor = new SlicesDatabaseAccessor(mContext);
final List<Uri> keys = accessor.getSliceUris(SettingsSliceProvider.SLICE_AUTHORITY);

View File

@@ -29,8 +29,8 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.DatabaseIndexingUtils;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexableData;
import com.android.settingslib.search.SearchIndexableResources;
import org.junit.Before;
@@ -60,10 +60,10 @@ public class PreferenceControllerContractTest {
final SearchIndexableResources resources =
FeatureFactory.getFactory(mContext).getSearchFeatureProvider()
.getSearchIndexableResources();
for (Class<?> clazz : resources.getProviderValues()) {
for (SearchIndexableData bundle : resources.getProviderValues()) {
final BaseSearchIndexProvider provider =
(BaseSearchIndexProvider) DatabaseIndexingUtils.getSearchIndexProvider(clazz);
(BaseSearchIndexProvider) bundle.getSearchIndexProvider();
if (provider == null) {
continue;
}

View File

@@ -32,8 +32,8 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.DatabaseIndexingUtils;
import com.android.settingslib.search.Indexable;
import com.android.settingslib.search.SearchIndexableData;
import com.android.settingslib.search.SearchIndexableRaw;
import com.android.settingslib.search.SearchIndexableResources;
@@ -120,8 +120,8 @@ public class UniquePreferenceTest {
final SearchIndexableResources resources =
FeatureFactory.getFactory(mContext).getSearchFeatureProvider()
.getSearchIndexableResources();
for (Class<?> clazz : resources.getProviderValues()) {
verifyPreferenceKeys(uniqueKeys, duplicatedKeys, nullKeyClasses, clazz);
for (SearchIndexableData SearchIndexableData : resources.getProviderValues()) {
verifyPreferenceKeys(uniqueKeys, duplicatedKeys, nullKeyClasses, SearchIndexableData);
}
if (!nullKeyClasses.isEmpty()) {
@@ -145,14 +145,12 @@ public class UniquePreferenceTest {
}
private void verifyPreferenceKeys(Set<String> uniqueKeys, Set<String> duplicatedKeys,
Set<String> nullKeyClasses, Class<?> clazz)
Set<String> nullKeyClasses, SearchIndexableData searchIndexableData)
throws IOException, XmlPullParserException, Resources.NotFoundException {
if (clazz == null) {
return;
}
final String className = clazz.getName();
final String className = searchIndexableData.getTargetClass().getName();
final Indexable.SearchIndexProvider provider =
DatabaseIndexingUtils.getSearchIndexProvider(clazz);
searchIndexableData.getSearchIndexProvider();
final List<SearchIndexableRaw> rawsToIndex = provider.getRawDataToIndex(mContext, true);
final List<SearchIndexableResource> resourcesToIndex =
provider.getXmlResourcesToIndex(mContext, true);

View File

@@ -33,8 +33,8 @@ import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.DatabaseIndexingUtils;
import com.android.settingslib.search.Indexable;
import com.android.settingslib.search.SearchIndexableData;
import com.android.settingslib.search.SearchIndexableResources;
import com.google.android.collect.Sets;
@@ -84,22 +84,21 @@ public class UserRestrictionTest {
final SearchIndexableResources resources =
FeatureFactory.getFactory(mContext).getSearchFeatureProvider()
.getSearchIndexableResources();
for (Class<?> clazz : resources.getProviderValues()) {
verifyUserRestriction(clazz);
for (SearchIndexableData bundle : resources.getProviderValues()) {
verifyUserRestriction(bundle);
}
}
private void verifyUserRestriction(Class<?> clazz)
private void verifyUserRestriction(SearchIndexableData searchIndexableData)
throws IOException, XmlPullParserException, Resources.NotFoundException {
if (clazz == null) {
return;
}
final String className = clazz.getName();
final Indexable.SearchIndexProvider provider =
DatabaseIndexingUtils.getSearchIndexProvider(clazz);
searchIndexableData.getSearchIndexProvider();
final List<SearchIndexableResource> resourcesToIndex =
provider.getXmlResourcesToIndex(mContext, true);
final String className = searchIndexableData.getTargetClass().getName();
if (resourcesToIndex == null) {
Log.d(TAG, className + "is not providing SearchIndexableResource, skipping");
return;

View File

@@ -31,8 +31,8 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.settings.core.PreferenceXmlParserUtils;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.DatabaseIndexingUtils;
import com.android.settingslib.search.Indexable;
import com.android.settingslib.search.SearchIndexableData;
import com.android.settingslib.search.SearchIndexableResources;
import org.junit.Before;
@@ -67,8 +67,8 @@ public class SliceDataContractTest {
FeatureFactory.getFactory(mContext).getSearchFeatureProvider()
.getSearchIndexableResources();
for (Class<?> clazz : resources.getProviderValues()) {
verifyPreferenceTitle(nullTitleFragments, clazz);
for (SearchIndexableData SearchIndexableData : resources.getProviderValues()) {
verifyPreferenceTitle(nullTitleFragments, SearchIndexableData);
}
if (!nullTitleFragments.isEmpty()) {
@@ -82,14 +82,13 @@ public class SliceDataContractTest {
}
}
private void verifyPreferenceTitle(Set<String> nullTitleFragments, Class<?> clazz)
private void verifyPreferenceTitle(Set<String> nullTitleFragments,
SearchIndexableData searchIndexableData)
throws IOException, XmlPullParserException {
if (clazz == null) {
return;
}
final String className = clazz.getName();
final String className = searchIndexableData.getTargetClass().getName();
final Indexable.SearchIndexProvider provider =
DatabaseIndexingUtils.getSearchIndexProvider(clazz);
searchIndexableData.getSearchIndexProvider();
final List<SearchIndexableResource> resourcesToIndex =
provider.getXmlResourcesToIndex(mContext, true);