Move Index provider conversion into Settings provider
Pre-patch, settings search provider would push all of its fragments into to search via SearchIndexableResources with an implicit contract of if the resource's xml == 0, then it was a settings fragment with an Index provider. One, implicit contract is bad. Two, it was messy at indexing time. So this patch moves htat conversion into the search index provider. Such that all of the indexables are either real Resources or Raw. Change-Id: I39f4351c03d123bb9b45edb4df7f924cfaff2b38 Fixes: 65376542 Fixes: 37741509 Test: robotests
This commit is contained in:
@@ -16,9 +16,7 @@
|
||||
|
||||
package com.android.settings.search;
|
||||
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.annotation.XmlRes;
|
||||
|
||||
import com.android.settings.DateTimeSettings;
|
||||
import com.android.settings.DeviceInfoSettings;
|
||||
@@ -88,22 +86,17 @@ import com.android.settings.wifi.ConfigureWifiSettings;
|
||||
import com.android.settings.wifi.WifiSettings;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public final class SearchIndexableResources {
|
||||
@XmlRes
|
||||
public static final int NO_RES_ID = 0;
|
||||
|
||||
@VisibleForTesting
|
||||
static final HashMap<String, SearchIndexableResource> sResMap = new HashMap<>();
|
||||
static final Set<Class> sProviders = new HashSet<>();
|
||||
|
||||
@VisibleForTesting
|
||||
static void addIndex(Class<?> indexClass) {
|
||||
String className = indexClass.getName();
|
||||
SearchIndexableResource resource = new SearchIndexableResource(
|
||||
0 /* rank */, NO_RES_ID, className, NO_RES_ID);
|
||||
|
||||
sResMap.put(className, resource);
|
||||
static void addIndex(Class indexClass) {
|
||||
sProviders.add(indexClass);
|
||||
}
|
||||
|
||||
static {
|
||||
@@ -178,15 +171,5 @@ public final class SearchIndexableResources {
|
||||
private SearchIndexableResources() {
|
||||
}
|
||||
|
||||
public static int size() {
|
||||
return sResMap.size();
|
||||
}
|
||||
|
||||
public static SearchIndexableResource getResourceByName(String className) {
|
||||
return sResMap.get(className);
|
||||
}
|
||||
|
||||
public static Collection<SearchIndexableResource> values() {
|
||||
return sResMap.values();
|
||||
}
|
||||
public static Collection<Class> providerValues() { return sProviders;}
|
||||
}
|
@@ -17,6 +17,19 @@
|
||||
package com.android.settings.search;
|
||||
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_CLASS_NAME;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_ENTRIES;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_ICON_RESID;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_INTENT_ACTION;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_INTENT_TARGET_CLASS;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_KEY;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_KEYWORDS;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SCREEN_TITLE;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SUMMARY_OFF;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SUMMARY_ON;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_TITLE;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_USER_ID;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_CLASS_NAME;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_ICON_RESID;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_ACTION;
|
||||
@@ -33,11 +46,12 @@ import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.provider.SearchIndexablesProvider;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider {
|
||||
@@ -60,8 +74,9 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider {
|
||||
@Override
|
||||
public Cursor queryXmlResources(String[] projection) {
|
||||
MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS);
|
||||
Collection<SearchIndexableResource> values = SearchIndexableResources.values();
|
||||
for (SearchIndexableResource val : values) {
|
||||
final List<SearchIndexableResource> resources =
|
||||
getSearchIndexableResourcesFromProvider(getContext());
|
||||
for (SearchIndexableResource val : resources) {
|
||||
Object[] ref = new Object[INDEXABLES_XML_RES_COLUMNS.length];
|
||||
ref[COLUMN_INDEX_XML_RES_RANK] = val.rank;
|
||||
ref[COLUMN_INDEX_XML_RES_RESID] = val.xmlResId;
|
||||
@@ -72,13 +87,33 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider {
|
||||
ref[COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS] = null; // intent target class
|
||||
cursor.addRow(ref);
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor queryRawData(String[] projection) {
|
||||
MatrixCursor result = new MatrixCursor(INDEXABLES_RAW_COLUMNS);
|
||||
return result;
|
||||
MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS);
|
||||
final List<SearchIndexableRaw> raws = getSearchIndexableRawFromProvider(getContext());
|
||||
for (SearchIndexableRaw val : raws) {
|
||||
Object[] ref = new Object[INDEXABLES_RAW_COLUMNS.length];
|
||||
ref[COLUMN_INDEX_RAW_TITLE] = val.title;
|
||||
ref[COLUMN_INDEX_RAW_SUMMARY_ON] = val.summaryOn;
|
||||
ref[COLUMN_INDEX_RAW_SUMMARY_OFF] = val.summaryOff;
|
||||
ref[COLUMN_INDEX_RAW_ENTRIES] = val.entries;
|
||||
ref[COLUMN_INDEX_RAW_KEYWORDS] = val.keywords;
|
||||
ref[COLUMN_INDEX_RAW_SCREEN_TITLE] = val.screenTitle;
|
||||
ref[COLUMN_INDEX_RAW_CLASS_NAME] = val.className;
|
||||
ref[COLUMN_INDEX_RAW_ICON_RESID] = val.iconResId;
|
||||
ref[COLUMN_INDEX_RAW_INTENT_ACTION] = val.intentAction;
|
||||
ref[COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE] = val.intentTargetPackage;
|
||||
ref[COLUMN_INDEX_RAW_INTENT_TARGET_CLASS] = val.intentTargetClass;
|
||||
ref[COLUMN_INDEX_RAW_KEY] = val.key;
|
||||
ref[COLUMN_INDEX_RAW_USER_ID] = val.userId;
|
||||
cursor.addRow(ref);
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,29 +124,24 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider {
|
||||
@Override
|
||||
public Cursor queryNonIndexableKeys(String[] projection) {
|
||||
MatrixCursor cursor = new MatrixCursor(NON_INDEXABLES_KEYS_COLUMNS);
|
||||
final Collection<String> values = new HashSet<>();
|
||||
final Context context = getContext();
|
||||
final List<String> nonIndexableKeys = getNonIndexableKeysFromProvider(getContext());
|
||||
for (String nik : nonIndexableKeys) {
|
||||
final Object[] ref = new Object[NON_INDEXABLES_KEYS_COLUMNS.length];
|
||||
ref[COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE] = nik;
|
||||
cursor.addRow(ref);
|
||||
}
|
||||
|
||||
for (SearchIndexableResource sir : SearchIndexableResources.values()) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Getting non-indexable from " + sir.className);
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
private List<String> getNonIndexableKeysFromProvider(Context context) {
|
||||
final Collection<Class> values = SearchIndexableResources.providerValues();
|
||||
final List<String> nonIndexableKeys = new ArrayList<>();
|
||||
|
||||
for (Class<?> clazz : values) {
|
||||
final long startTime = System.currentTimeMillis();
|
||||
final Class<?> clazz = DatabaseIndexingUtils.getIndexableClass(sir.className);
|
||||
if (clazz == null) {
|
||||
Log.d(TAG, "SearchIndexableResource '" + sir.className +
|
||||
"' should implement the " + Indexable.class.getName() + " interface!");
|
||||
continue;
|
||||
}
|
||||
|
||||
final Indexable.SearchIndexProvider provider =
|
||||
DatabaseIndexingUtils.getSearchIndexProvider(clazz);
|
||||
|
||||
if (provider == null) {
|
||||
Log.d(TAG, "Unable to get SearchIndexableProvider from " + clazz);
|
||||
continue;
|
||||
}
|
||||
|
||||
Indexable.SearchIndexProvider provider = DatabaseIndexingUtils.getSearchIndexProvider(
|
||||
clazz);
|
||||
List<String> providerNonIndexableKeys = provider.getNonIndexableKeys(context);
|
||||
|
||||
if (providerNonIndexableKeys == null || providerNonIndexableKeys.isEmpty()) {
|
||||
@@ -123,22 +153,71 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider {
|
||||
}
|
||||
|
||||
if (providerNonIndexableKeys.removeAll(INVALID_KEYS)) {
|
||||
Log.v(TAG, clazz.getName() + " tried to add an empty non-indexable key");
|
||||
Log.v(TAG, provider + " tried to add an empty non-indexable key");
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
final long totalTime = System.currentTimeMillis() - startTime;
|
||||
Log.d(TAG, "Non-indexables " + providerNonIndexableKeys.size() + ", total time "
|
||||
+ totalTime);
|
||||
}
|
||||
values.addAll(providerNonIndexableKeys);
|
||||
|
||||
nonIndexableKeys.addAll(providerNonIndexableKeys);
|
||||
}
|
||||
|
||||
for (String nik : values) {
|
||||
return nonIndexableKeys;
|
||||
}
|
||||
|
||||
final Object[] ref = new Object[NON_INDEXABLES_KEYS_COLUMNS.length];
|
||||
ref[COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE] = nik;
|
||||
cursor.addRow(ref);
|
||||
private List<SearchIndexableResource> getSearchIndexableResourcesFromProvider(Context context) {
|
||||
Collection<Class> values = SearchIndexableResources.providerValues();
|
||||
List<SearchIndexableResource> resourceList = new ArrayList<>();
|
||||
|
||||
for (Class<?> clazz : values) {
|
||||
Indexable.SearchIndexProvider provider = DatabaseIndexingUtils.getSearchIndexProvider(
|
||||
clazz);
|
||||
|
||||
final List<SearchIndexableResource> resList =
|
||||
provider.getXmlResourcesToIndex(context, true);
|
||||
|
||||
if (resList == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (SearchIndexableResource item : resList) {
|
||||
item.className = TextUtils.isEmpty(item.className)
|
||||
? clazz.getName()
|
||||
: item.className;
|
||||
}
|
||||
|
||||
resourceList.addAll(resList);
|
||||
}
|
||||
return cursor;
|
||||
|
||||
return resourceList;
|
||||
}
|
||||
|
||||
private List<SearchIndexableRaw> getSearchIndexableRawFromProvider(Context context) {
|
||||
final Collection<Class> values = SearchIndexableResources.providerValues();
|
||||
final List<SearchIndexableRaw> rawList = new ArrayList<>();
|
||||
|
||||
for (Class<?> clazz : values) {
|
||||
Indexable.SearchIndexProvider provider = DatabaseIndexingUtils.getSearchIndexProvider(
|
||||
clazz);
|
||||
final List<SearchIndexableRaw> providerRaws = provider.getRawDataToIndex(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 = clazz.getName();
|
||||
|
||||
}
|
||||
rawList.addAll(providerRaws);
|
||||
}
|
||||
|
||||
return rawList;
|
||||
}
|
||||
}
|
||||
|
@@ -31,7 +31,6 @@ import android.util.Xml;
|
||||
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.search.Indexable;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settings.search.SearchIndexableRaw;
|
||||
import com.android.settings.search.XmlParserUtils;
|
||||
@@ -89,21 +88,8 @@ public class IndexDataConverter {
|
||||
final SearchIndexableResource sir = (SearchIndexableResource) data;
|
||||
final Set<String> resourceNonIndexableKeys =
|
||||
getNonIndexableKeysForResource(nonIndexableKeys, sir.packageName);
|
||||
|
||||
if (sir.xmlResId == 0) {
|
||||
// Index from provider
|
||||
final Indexable.SearchIndexProvider provider = getSearchProvider(sir);
|
||||
if (provider == null) {
|
||||
continue;
|
||||
}
|
||||
indexData.addAll(convertIndexProvider(provider, sir, resourceNonIndexableKeys));
|
||||
|
||||
} else {
|
||||
final List<IndexData> resourceData = convertResource(sir,
|
||||
resourceNonIndexableKeys);
|
||||
indexData.addAll(resourceData);
|
||||
}
|
||||
|
||||
final List<IndexData> resourceData = convertResource(sir, resourceNonIndexableKeys);
|
||||
indexData.addAll(resourceData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,84 +291,10 @@ public class IndexDataConverter {
|
||||
return resourceIndexData;
|
||||
}
|
||||
|
||||
private List<IndexData> convertIndexProvider(Indexable.SearchIndexProvider provider,
|
||||
SearchIndexableResource sir, Set<String> nonIndexableKeys) {
|
||||
final List<IndexData> indexData = new ArrayList<>();
|
||||
|
||||
final String className = sir.className;
|
||||
final String intentAction = sir.intentAction;
|
||||
final String intentTargetPackage = sir.intentTargetPackage;
|
||||
|
||||
// TODO (b/65376542) Move provider conversion to PreIndexTime
|
||||
// TODO (b/37741509) Providers don't use general non-indexable keys
|
||||
nonIndexableKeys.addAll(provider.getNonIndexableKeys(mContext));
|
||||
|
||||
final List<SearchIndexableRaw> rawList = provider.getRawDataToIndex(mContext,
|
||||
true /* enabled */);
|
||||
|
||||
if (rawList != null) {
|
||||
for (SearchIndexableRaw raw : rawList) {
|
||||
// The classname and intent information comes from the PreIndexData
|
||||
// This will be more clear when provider conversion is done at PreIndex time.
|
||||
raw.className = className;
|
||||
raw.intentAction = intentAction;
|
||||
raw.intentTargetPackage = intentTargetPackage;
|
||||
|
||||
IndexData.Builder builder = convertRaw(raw, nonIndexableKeys);
|
||||
if (builder != null) {
|
||||
indexData.add(builder.build(mContext));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final List<SearchIndexableResource> resList =
|
||||
provider.getXmlResourcesToIndex(mContext, true);
|
||||
|
||||
if (resList != null) {
|
||||
for (SearchIndexableResource item : resList) {
|
||||
item.className = TextUtils.isEmpty(item.className)
|
||||
? className
|
||||
: item.className;
|
||||
item.intentAction = TextUtils.isEmpty(item.intentAction)
|
||||
? intentAction
|
||||
: item.intentAction;
|
||||
item.intentTargetPackage = TextUtils.isEmpty(item.intentTargetPackage)
|
||||
? intentTargetPackage
|
||||
: item.intentTargetPackage;
|
||||
|
||||
indexData.addAll(convertResource(item, nonIndexableKeys));
|
||||
}
|
||||
}
|
||||
|
||||
return indexData;
|
||||
}
|
||||
|
||||
private Set<String> getNonIndexableKeysForResource(Map<String, Set<String>> nonIndexableKeys,
|
||||
String packageName) {
|
||||
return nonIndexableKeys.containsKey(packageName)
|
||||
? nonIndexableKeys.get(packageName)
|
||||
: new HashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Return the {@link Indexable.SearchIndexProvider} corresponding to the
|
||||
* class specified by the Class name specified by {@param sir}.
|
||||
*/
|
||||
private Indexable.SearchIndexProvider getSearchProvider(SearchIndexableResource sir) {
|
||||
if (TextUtils.isEmpty(sir.className)) {
|
||||
Log.w(LOG_TAG, "Cannot index an empty Search Provider name!");
|
||||
return null;
|
||||
}
|
||||
|
||||
final Class<?> clazz = DatabaseIndexingUtils.getIndexableClass(sir.className);
|
||||
if (clazz == null) {
|
||||
Log.d(LOG_TAG, "SearchIndexableResource '" + sir.className +
|
||||
"' should implement the " + Indexable.class.getName() + " interface!");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Will be non null only for a Local provider implementing a
|
||||
// SEARCH_INDEX_DATA_PROVIDER field
|
||||
return DatabaseIndexingUtils.getSearchIndexProvider(clazz);
|
||||
}
|
||||
}
|
||||
|
@@ -114,11 +114,10 @@ public class SearchIndexProviderCodeInspector extends CodeInspector {
|
||||
continue;
|
||||
}
|
||||
// Must be in SearchProviderRegistry
|
||||
if (SearchIndexableResources.getResourceByName(className) == null) {
|
||||
if (!SearchIndexableResources.providerValues().contains(clazz)) {
|
||||
if (!notInSearchIndexableRegistryGrandfatherList.remove(className)) {
|
||||
notInSearchProviderRegistry.add(className);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -17,12 +17,13 @@
|
||||
package com.android.settings.search;
|
||||
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE;
|
||||
import static com.android.settings.search.SearchIndexableResources.NO_RES_ID;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static junit.framework.Assert.fail;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.settings.TestConfig;
|
||||
@@ -35,60 +36,48 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class SearchIndexableResourcesTest {
|
||||
|
||||
Map<String, SearchIndexableResource> sResMapCopy;
|
||||
Set<Class> sProviderClassCopy;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
sResMapCopy = new HashMap<>(SearchIndexableResources.sResMap);
|
||||
sProviderClassCopy = new HashSet<>(SearchIndexableResources.sProviders);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
SearchIndexableResources.sResMap.clear();
|
||||
for (String key : sResMapCopy.keySet()) {
|
||||
SearchIndexableResources.sResMap.put(key, sResMapCopy.get(key));
|
||||
}
|
||||
SearchIndexableResources.sProviders.clear();
|
||||
SearchIndexableResources.sProviders.addAll(sProviderClassCopy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddIndex() {
|
||||
final Class stringClass = java.lang.String.class;
|
||||
// Confirms that String.class isn't contained in SearchIndexableResources.
|
||||
assertThat(SearchIndexableResources.getResourceByName("java.lang.String")).isNull();
|
||||
final int beforeCount = SearchIndexableResources.values().size();
|
||||
assertThat(SearchIndexableResources.sProviders).doesNotContain(stringClass);
|
||||
final int beforeCount = SearchIndexableResources.providerValues().size();
|
||||
|
||||
SearchIndexableResources.addIndex(java.lang.String.class);
|
||||
final SearchIndexableResource index = SearchIndexableResources
|
||||
.getResourceByName("java.lang.String");
|
||||
|
||||
assertThat(index).isNotNull();
|
||||
assertThat(index.className).isEqualTo("java.lang.String");
|
||||
assertThat(index.xmlResId).isEqualTo(NO_RES_ID);
|
||||
assertThat(index.iconResId).isEqualTo(NO_RES_ID);
|
||||
final int afterCount = SearchIndexableResources.values().size();
|
||||
assertThat(SearchIndexableResources.sProviders).contains(stringClass);
|
||||
final int afterCount = SearchIndexableResources.providerValues().size();
|
||||
assertThat(afterCount).isEqualTo(beforeCount + 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexHasWifiSettings() {
|
||||
final SearchIndexableResource index = SearchIndexableResources
|
||||
.getResourceByName(WifiSettings.class.getName());
|
||||
|
||||
assertThat(index).isNotNull();
|
||||
assertThat(index.className).isEqualTo(WifiSettings.class.getName());
|
||||
assertThat(index.xmlResId).isEqualTo(NO_RES_ID);
|
||||
assertThat(index.iconResId).isEqualTo(NO_RES_ID);
|
||||
assertThat(sProviderClassCopy).contains(WifiSettings.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonIndexableKeys_GetsKeyFromProvider() {
|
||||
SearchIndexableResources.sResMap.clear();
|
||||
SearchIndexableResources.sProviders.clear();
|
||||
SearchIndexableResources.addIndex(FakeIndexProvider.class);
|
||||
|
||||
SettingsSearchIndexablesProvider provider = spy(new SettingsSearchIndexablesProvider());
|
||||
@@ -105,4 +94,13 @@ public class SearchIndexableResourcesTest {
|
||||
|
||||
assertThat(hasTestKey).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllClassNamesHaveProviders() {
|
||||
for (Class clazz: sProviderClassCopy) {
|
||||
if(DatabaseIndexingUtils.getSearchIndexProvider(clazz) == null) {
|
||||
fail(clazz.getName() + "is not an index provider");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,119 @@
|
||||
package com.android.settings.search;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.SearchIndexablesContract;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.search.indexing.FakeSettingsFragment;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class SettingsSearchIndexablesProviderTest {
|
||||
|
||||
private final String BASE_AUTHORITY = "com.android.settings";
|
||||
|
||||
private SettingsSearchIndexablesProvider mProvider;
|
||||
|
||||
Set<Class> sProviderClasses;
|
||||
Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
|
||||
mProvider = spy(new SettingsSearchIndexablesProvider());
|
||||
ProviderInfo info = new ProviderInfo();
|
||||
info.exported = true;
|
||||
info.grantUriPermissions = true;
|
||||
info.authority = BASE_AUTHORITY;
|
||||
info.readPermission = Manifest.permission.READ_SEARCH_INDEXABLES;
|
||||
mProvider.attachInfo(mContext, info);
|
||||
|
||||
sProviderClasses = new HashSet<>(SearchIndexableResources.sProviders);
|
||||
SearchIndexableResources.sProviders.clear();
|
||||
SearchIndexableResources.sProviders.add(FakeSettingsFragment.class);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
SearchIndexableResources.sProviders.clear();
|
||||
SearchIndexableResources.sProviders.addAll(sProviderClasses);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawColumnFetched() {
|
||||
Uri rawUri = Uri.parse("content://" + BASE_AUTHORITY + "/" +
|
||||
SearchIndexablesContract.INDEXABLES_RAW_PATH);
|
||||
|
||||
final Cursor cursor = mProvider.query(rawUri,
|
||||
SearchIndexablesContract.INDEXABLES_RAW_COLUMNS, null, null, null);
|
||||
|
||||
cursor.moveToFirst();
|
||||
assertThat(cursor.getString(1)).isEqualTo(FakeSettingsFragment.TITLE);
|
||||
assertThat(cursor.getString(2)).isEqualTo(FakeSettingsFragment.SUMMARY_ON);
|
||||
assertThat(cursor.getString(3)).isEqualTo(FakeSettingsFragment.SUMMARY_OFF);
|
||||
assertThat(cursor.getString(4)).isEqualTo(FakeSettingsFragment.ENTRIES);
|
||||
assertThat(cursor.getString(5)).isEqualTo(FakeSettingsFragment.KEYWORDS);
|
||||
assertThat(cursor.getString(6)).isEqualTo(FakeSettingsFragment.SCREEN_TITLE);
|
||||
assertThat(cursor.getString(7)).isEqualTo(FakeSettingsFragment.CLASS_NAME);
|
||||
assertThat(cursor.getInt(8)).isEqualTo(FakeSettingsFragment.ICON);
|
||||
assertThat(cursor.getString(9)).isEqualTo(FakeSettingsFragment.INTENT_ACTION);
|
||||
assertThat(cursor.getString(10)).isEqualTo(FakeSettingsFragment.TARGET_PACKAGE);
|
||||
assertThat(cursor.getString(11)).isEqualTo(FakeSettingsFragment.TARGET_CLASS);
|
||||
assertThat(cursor.getString(12)).isEqualTo(FakeSettingsFragment.KEY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResourcesColumnFetched() {
|
||||
Uri rawUri = Uri.parse("content://" + BASE_AUTHORITY + "/" +
|
||||
SearchIndexablesContract.INDEXABLES_XML_RES_PATH);
|
||||
|
||||
final Cursor cursor = mProvider.query(rawUri,
|
||||
SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS, null, null, null);
|
||||
|
||||
cursor.moveToFirst();
|
||||
assertThat(cursor.getCount()).isEqualTo(1);
|
||||
assertThat(cursor.getInt(1)).isEqualTo(R.xml.display_settings);
|
||||
assertThat(cursor.getString(2)).isEqualTo(FakeSettingsFragment.CLASS_NAME);
|
||||
assertThat(cursor.getInt(3)).isEqualTo(0);
|
||||
assertThat(cursor.getString(4)).isNull();
|
||||
assertThat(cursor.getString(5)).isNull();
|
||||
assertThat(cursor.getString(6)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonIndexablesColumnFetched() {
|
||||
Uri rawUri = Uri.parse("content://" + BASE_AUTHORITY + "/" +
|
||||
SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH);
|
||||
//final ContentResolver resolver = mContext.getContentResolver();
|
||||
|
||||
final Cursor cursor = mProvider.query(rawUri,
|
||||
SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS, null, null, null);
|
||||
|
||||
cursor.moveToFirst();
|
||||
assertThat(cursor.getCount()).isEqualTo(2);
|
||||
assertThat(cursor.getString(0)).isEqualTo("pref_key_1");
|
||||
cursor.moveToNext();
|
||||
assertThat(cursor.getString(0)).isEqualTo("pref_key_3");
|
||||
}
|
||||
}
|
@@ -266,55 +266,6 @@ public class IndexDataConverterTest {
|
||||
assertThat(row.iconResId).isGreaterThan(0);
|
||||
}
|
||||
|
||||
// Tests for the flow: IndexOneResource -> IndexFromProvider -> IndexFromResource ->
|
||||
// UpdateOneRowWithFilteredData -> UpdateOneRow
|
||||
|
||||
@Test
|
||||
public void testAddProviderWithResource_rowInserted() {
|
||||
final SearchIndexableResource resource = getFakeResource(0 /* xml */);
|
||||
resource.className = FAKE_CLASS_NAME;
|
||||
final PreIndexData preIndexData = new PreIndexData();
|
||||
preIndexData.dataToUpdate.add(resource);
|
||||
|
||||
List<IndexData> indexData = mConverter.convertPreIndexDataToIndexData(preIndexData);
|
||||
|
||||
assertThat(indexData.size()).isEqualTo(NUM_FAKE_FRAGMENT_ENTRIES);
|
||||
assertThat(findIndexDataForTitle(indexData, PAGE_TITLE)).isNotNull();
|
||||
assertThat(findIndexDataForTitle(indexData, TITLE_ONE)).isNotNull();
|
||||
assertThat(findIndexDataForTitle(indexData, TITLE_TWO)).isNotNull();
|
||||
assertThat(findIndexDataForTitle(indexData, TITLE_THREE)).isNotNull();
|
||||
assertThat(findIndexDataForTitle(indexData, TITLE_FOUR)).isNotNull();
|
||||
assertThat(findIndexDataForTitle(indexData, TITLE_FIVE)).isNotNull();
|
||||
assertThat(findIndexDataForTitle(indexData, FakeSettingsFragment.TITLE)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddProviderWithRaw_rowInserted() {
|
||||
final SearchIndexableResource resource = getFakeResource(0 /* xml */);
|
||||
resource.className = FAKE_CLASS_NAME;
|
||||
final PreIndexData preIndexData = new PreIndexData();
|
||||
preIndexData.dataToUpdate.add(resource);
|
||||
|
||||
List<IndexData> indexData = mConverter.convertPreIndexDataToIndexData(preIndexData);
|
||||
|
||||
final IndexData data = findIndexDataForTitle(indexData, FakeSettingsFragment.TITLE);
|
||||
assertFakeFragment(data);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddProvider_disabledRows() {
|
||||
// Note that in FakeSettingsFragment, preferences 1 and 3 are disabled.
|
||||
final SearchIndexableResource resource = getFakeResource(0 /* xml */);
|
||||
resource.className = FAKE_CLASS_NAME;
|
||||
|
||||
final PreIndexData preIndexData = new PreIndexData();
|
||||
preIndexData.dataToUpdate.add(resource);
|
||||
|
||||
List<IndexData> indexData = mConverter.convertPreIndexDataToIndexData(preIndexData);
|
||||
|
||||
assertThat(getEnabledResultCount(indexData)).isEqualTo(NUM_ENABLED_FAKE_FRAGMENT_ENTRIES);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResource_sameTitleForSettingAndPage_titleNotInserted() {
|
||||
final SearchIndexableResource resource = getFakeResource(R.xml.about_legal);
|
||||
|
@@ -54,8 +54,7 @@ public class PreferenceControllerContractTest {
|
||||
public void controllersInSearchShouldImplementPreferenceControllerMixin() {
|
||||
final Set<String> errorClasses = new ArraySet<>();
|
||||
|
||||
for (SearchIndexableResource page : SearchIndexableResources.values()) {
|
||||
final Class<?> clazz = DatabaseIndexingUtils.getIndexableClass(page.className);
|
||||
for (Class clazz: SearchIndexableResources.providerValues()) {
|
||||
|
||||
final Indexable.SearchIndexProvider provider =
|
||||
DatabaseIndexingUtils.getSearchIndexProvider(clazz);
|
||||
|
@@ -90,8 +90,8 @@ public class UniquePreferenceTest {
|
||||
final Set<String> uniqueKeys = new HashSet<>();
|
||||
final Set<String> nullKeyClasses = new HashSet<>();
|
||||
final Set<String> duplicatedKeys = new HashSet<>();
|
||||
for (SearchIndexableResource sir : SearchIndexableResources.values()) {
|
||||
verifyPreferenceIdInXml(uniqueKeys, duplicatedKeys, nullKeyClasses, sir);
|
||||
for (Class<?> clazz : SearchIndexableResources.providerValues()) {
|
||||
verifyPreferenceIdInXml(uniqueKeys, duplicatedKeys, nullKeyClasses, clazz);
|
||||
}
|
||||
|
||||
if (!nullKeyClasses.isEmpty()) {
|
||||
@@ -115,22 +115,24 @@ public class UniquePreferenceTest {
|
||||
}
|
||||
|
||||
private void verifyPreferenceIdInXml(Set<String> uniqueKeys, Set<String> duplicatedKeys,
|
||||
Set<String> nullKeyClasses, SearchIndexableResource page)
|
||||
Set<String> nullKeyClasses, Class<?> clazz)
|
||||
throws IOException, XmlPullParserException, Resources.NotFoundException {
|
||||
final Class<?> clazz = DatabaseIndexingUtils.getIndexableClass(page.className);
|
||||
|
||||
if (clazz == null) {
|
||||
return;
|
||||
}
|
||||
final String className = clazz.getName();
|
||||
final Indexable.SearchIndexProvider provider =
|
||||
DatabaseIndexingUtils.getSearchIndexProvider(clazz);
|
||||
final List<SearchIndexableResource> resourcesToIndex =
|
||||
provider.getXmlResourcesToIndex(mContext, true);
|
||||
if (resourcesToIndex == null) {
|
||||
Log.d(TAG, page.className + "is not providing SearchIndexableResource, skipping");
|
||||
Log.d(TAG, className + "is not providing SearchIndexableResource, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
for (SearchIndexableResource sir : resourcesToIndex) {
|
||||
if (sir.xmlResId <= 0) {
|
||||
Log.d(TAG, page.className + " doesn't have a valid xml to index.");
|
||||
Log.d(TAG, className + " doesn't have a valid xml to index.");
|
||||
continue;
|
||||
}
|
||||
final XmlResourceParser parser = mContext.getResources().getXml(sir.xmlResId);
|
||||
@@ -154,14 +156,14 @@ public class UniquePreferenceTest {
|
||||
final String key = XmlParserUtils.getDataKey(mContext, attrs);
|
||||
if (TextUtils.isEmpty(key)) {
|
||||
Log.e(TAG, "Every preference must have an key; found null key"
|
||||
+ " in " + page.className
|
||||
+ " in " + className
|
||||
+ " at " + parser.getPositionDescription());
|
||||
nullKeyClasses.add(page.className);
|
||||
nullKeyClasses.add(className);
|
||||
continue;
|
||||
}
|
||||
if (uniqueKeys.contains(key) && !WHITELISTED_DUPLICATE_KEYS.contains(key)) {
|
||||
Log.e(TAG, "Every preference key must unique; found " + nodeName
|
||||
+ " in " + page.className
|
||||
+ " in " + className
|
||||
+ " at " + parser.getPositionDescription());
|
||||
duplicatedKeys.add(key);
|
||||
}
|
||||
|
Reference in New Issue
Block a user