Update SettingsSearchIndexablesProvider for supporting queryNonIndexableKeys(...)

- add the new requested method "queryNonIndexableKeys" from the contract

Change-Id: I72be47851a7e19e3f14960f4e2b60c3e952f1fac
This commit is contained in:
Fabrice Di Meglio
2014-04-11 18:49:10 -07:00
parent 210bb8694a
commit df278aa959
3 changed files with 185 additions and 102 deletions

View File

@@ -408,7 +408,6 @@ public class SettingsActivity extends Activity
if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) { if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) {
getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0)); getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
} }
Index.getInstance(this).update(); Index.getInstance(this).update();
mAuthenticatorHelper = new AuthenticatorHelper(); mAuthenticatorHelper = new AuthenticatorHelper();

View File

@@ -47,11 +47,14 @@ import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_RANK; import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_RANK;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_TITLE; import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_TITLE;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SUMMARY_ON; import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SUMMARY_ON;
@@ -150,16 +153,20 @@ public class Index {
private class UpdateData { private class UpdateData {
public List<SearchIndexableData> dataToUpdate; public List<SearchIndexableData> dataToUpdate;
public List<String> dataToDelete; public List<String> dataToDelete;
public Map<String, List<String>> nonIndexableKeys;
public boolean forceUpdate = false; public boolean forceUpdate = false;
public UpdateData() { public UpdateData() {
dataToUpdate = new ArrayList<SearchIndexableData>(); dataToUpdate = new ArrayList<SearchIndexableData>();
dataToDelete = new ArrayList<String>(); dataToDelete = new ArrayList<String>();
nonIndexableKeys = new HashMap<String, List<String>>();
} }
public void clear() { public void clear() {
dataToUpdate.clear(); dataToUpdate.clear();
dataToDelete.clear(); dataToDelete.clear();
nonIndexableKeys.clear();
forceUpdate = false; forceUpdate = false;
} }
} }
@@ -194,6 +201,94 @@ public class Index {
return getReadableDatabase().rawQuery(sql, null); return getReadableDatabase().rawQuery(sql, null);
} }
public boolean update() {
final Intent intent = new Intent(SearchIndexablesContract.PROVIDER_INTERFACE);
List<ResolveInfo> list =
mContext.getPackageManager().queryIntentContentProviders(intent, 0);
final int size = list.size();
for (int n = 0; n < size; n++) {
final ResolveInfo info = list.get(n);
if (!isWellKnownProvider(info)) {
continue;
}
final String authority = info.providerInfo.authority;
final String packageName = info.providerInfo.packageName;
addIndexablesFromRemoteProvider(packageName, authority);
addNonIndexablesKeysFromRemoteProvider(packageName, authority);
}
return updateInternal();
}
private boolean addIndexablesFromRemoteProvider(String packageName, String authority) {
try {
final Context packageContext = mContext.createPackageContext(packageName, 0);
final Uri uriForResources = buildUriForXmlResources(authority);
addIndexablesForXmlResourceUri(packageContext, packageName, uriForResources,
SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS);
final Uri uriForRawData = buildUriForRawData(authority);
addIndexablesForRawDataUri(packageContext, packageName, uriForRawData,
SearchIndexablesContract.INDEXABLES_RAW_COLUMNS);
return true;
} catch (PackageManager.NameNotFoundException e) {
Log.w(LOG_TAG, "Could not create context for " + packageName + ": "
+ Log.getStackTraceString(e));
return false;
}
}
private void addNonIndexablesKeysFromRemoteProvider(String packageName,
String authority) {
final List<String> keys =
getNonIndexablesKeysFromRemoteProvider(packageName, authority);
addNonIndexableKeys(packageName, keys);
}
private List<String> getNonIndexablesKeysFromRemoteProvider(String packageName,
String authority) {
try {
final Context packageContext = mContext.createPackageContext(packageName, 0);
final Uri uriForNonIndexableKeys = buildUriForNonIndexableKeys(authority);
return getNonIndexablesKeys(packageContext, uriForNonIndexableKeys,
SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS);
} catch (PackageManager.NameNotFoundException e) {
Log.w(LOG_TAG, "Could not create context for " + packageName + ": "
+ Log.getStackTraceString(e));
return EMPTY_LIST;
}
}
private List<String> getNonIndexablesKeys(Context packageContext, Uri uri,
String[] projection) {
final ContentResolver resolver = packageContext.getContentResolver();
final Cursor cursor = resolver.query(uri, projection, null, null, null);
if (cursor == null) {
Log.w(LOG_TAG, "Cannot add index data for Uri: " + uri.toString());
return EMPTY_LIST;
}
List<String> result = new ArrayList<String>();
try {
final int count = cursor.getCount();
if (count > 0) {
while (cursor.moveToNext()) {
final String key = cursor.getString(COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE);
result.add(key);
}
}
return result;
} finally {
cursor.close();
}
}
public void addIndexableData(SearchIndexableData data) { public void addIndexableData(SearchIndexableData data) {
synchronized (mDataToProcess) { synchronized (mDataToProcess) {
mDataToProcess.dataToUpdate.add(data); mDataToProcess.dataToUpdate.add(data);
@@ -218,23 +313,10 @@ public class Index {
} }
} }
public boolean update() { public void addNonIndexableKeys(String authority, List<String> keys) {
final Intent intent = new Intent(SearchIndexablesContract.PROVIDER_INTERFACE); synchronized (mDataToProcess) {
List<ResolveInfo> list = mDataToProcess.nonIndexableKeys.put(authority, keys);
mContext.getPackageManager().queryIntentContentProviders(intent, 0);
final int size = list.size();
for (int n = 0; n < size; n++) {
final ResolveInfo info = list.get(n);
if (!isWellKnownProvider(info)) {
continue;
}
final String authority = info.providerInfo.authority;
final String packageName = info.providerInfo.packageName;
addIndexablesFromRemoteProvider(packageName, authority);
} }
return updateInternal();
} }
/** /**
@@ -314,26 +396,6 @@ public class Index {
return IndexDatabaseHelper.getInstance(mContext).getWritableDatabase(); return IndexDatabaseHelper.getInstance(mContext).getWritableDatabase();
} }
private boolean addIndexablesFromRemoteProvider(String packageName, String authority) {
final Context packageContext;
try {
packageContext = mContext.createPackageContext(packageName, 0);
final Uri uriForResources = buildUriForXmlResources(authority);
addIndexablesForXmlResourceUri(packageContext, packageName, uriForResources,
SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS);
final Uri uriForRawData = buildUriForRawData(authority);
addIndexablesForRawDataUri(packageContext, packageName, uriForRawData,
SearchIndexablesContract.INDEXABLES_RAW_COLUMNS);
return true;
} catch (PackageManager.NameNotFoundException e) {
Log.w(LOG_TAG, "Could not create context for " + packageName + ": "
+ Log.getStackTraceString(e));
return false;
}
}
private static Uri buildUriForXmlResources(String authority) { private static Uri buildUriForXmlResources(String authority) {
return Uri.parse("content://" + authority + "/" + return Uri.parse("content://" + authority + "/" +
SearchIndexablesContract.INDEXABLES_XML_RES_PATH); SearchIndexablesContract.INDEXABLES_XML_RES_PATH);
@@ -344,6 +406,11 @@ public class Index {
SearchIndexablesContract.INDEXABLES_RAW_PATH); SearchIndexablesContract.INDEXABLES_RAW_PATH);
} }
private static Uri buildUriForNonIndexableKeys(String authority) {
return Uri.parse("content://" + authority + "/" +
SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH);
}
private boolean updateInternal() { private boolean updateInternal() {
synchronized (mDataToProcess) { synchronized (mDataToProcess) {
final UpdateIndexTask task = new UpdateIndexTask(); final UpdateIndexTask task = new UpdateIndexTask();
@@ -366,8 +433,7 @@ public class Index {
Uri uri, String[] projection) { Uri uri, String[] projection) {
final ContentResolver resolver = packageContext.getContentResolver(); final ContentResolver resolver = packageContext.getContentResolver();
final Cursor cursor = resolver.query(uri, projection, final Cursor cursor = resolver.query(uri, projection, null, null, null);
null, null, null);
if (cursor == null) { if (cursor == null) {
Log.w(LOG_TAG, "Cannot add index data for Uri: " + uri.toString()); Log.w(LOG_TAG, "Cannot add index data for Uri: " + uri.toString());
@@ -412,8 +478,7 @@ public class Index {
Uri uri, String[] projection) { Uri uri, String[] projection) {
final ContentResolver resolver = packageContext.getContentResolver(); final ContentResolver resolver = packageContext.getContentResolver();
final Cursor cursor = resolver.query(uri, projection, final Cursor cursor = resolver.query(uri, projection, null, null, null);
null, null, null);
if (cursor == null) { if (cursor == null) {
Log.w(LOG_TAG, "Cannot add index data for Uri: " + uri.toString()); Log.w(LOG_TAG, "Cannot add index data for Uri: " + uri.toString());
@@ -523,16 +588,40 @@ public class Index {
} }
private void indexOneSearchIndexableData(SQLiteDatabase database, String localeStr, private void indexOneSearchIndexableData(SQLiteDatabase database, String localeStr,
SearchIndexableData data) { SearchIndexableData data, Map<String, List<String>> nonIndexableKeys) {
if (data instanceof SearchIndexableResource) { if (data instanceof SearchIndexableResource) {
indexOneResource(database, localeStr, (SearchIndexableResource) data); indexOneResource(database, localeStr, (SearchIndexableResource) data, nonIndexableKeys);
} else if (data instanceof SearchIndexableRaw) { } else if (data instanceof SearchIndexableRaw) {
indexOneRaw(database, localeStr, (SearchIndexableRaw) data); indexOneRaw(database, localeStr, (SearchIndexableRaw) data);
} }
} }
private void indexOneRaw(SQLiteDatabase database, String localeStr,
SearchIndexableRaw raw) {
// Should be the same locale as the one we are processing
if (!raw.locale.toString().equalsIgnoreCase(localeStr)) {
return;
}
updateOneRowWithFilteredData(database, localeStr,
raw.title,
raw.summaryOn,
raw.summaryOff,
raw.entries,
raw.className,
raw.screenTitle,
raw.iconResId,
raw.rank,
raw.keywords,
raw.intentAction,
raw.intentTargetPackage,
raw.intentTargetClass,
raw.enabled,
raw.key);
}
private void indexOneResource(SQLiteDatabase database, String localeStr, private void indexOneResource(SQLiteDatabase database, String localeStr,
SearchIndexableResource sir) { SearchIndexableResource sir, Map<String, List<String>> nonIndexableKeysFromResource) {
if (sir == null) { if (sir == null) {
Log.e(LOG_TAG, "Cannot index a null resource!"); Log.e(LOG_TAG, "Cannot index a null resource!");
@@ -543,25 +632,51 @@ public class Index {
final Indexable.SearchIndexProvider provider = final Indexable.SearchIndexProvider provider =
TextUtils.isEmpty(sir.className) ? null : getSearchIndexProvider(sir.className); TextUtils.isEmpty(sir.className) ? null : getSearchIndexProvider(sir.className);
List<String> nonIndexableKeys = new ArrayList<String>();
if (sir.xmlResId > SearchIndexableResources.NO_DATA_RES_ID) { if (sir.xmlResId > SearchIndexableResources.NO_DATA_RES_ID) {
List<String> doNotIndexKeys = EMPTY_LIST; List<String> resNonIndxableKeys = nonIndexableKeysFromResource.get(sir.packageName);
if (provider != null) { if (resNonIndxableKeys != null && resNonIndxableKeys.size() > 0) {
doNotIndexKeys = provider.getNonIndexableKeys(sir.context); nonIndexableKeys.addAll(resNonIndxableKeys);
} }
indexFromResource(sir.context, database, localeStr, indexFromResource(sir.context, database, localeStr,
sir.xmlResId, sir.className, sir.iconResId, sir.rank, sir.xmlResId, sir.className, sir.iconResId, sir.rank,
sir.intentAction, sir.intentTargetPackage, sir.intentTargetClass, sir.intentAction, sir.intentTargetPackage, sir.intentTargetClass,
doNotIndexKeys); nonIndexableKeys);
} else if (!TextUtils.isEmpty(sir.className)) { } else if (!TextUtils.isEmpty(sir.className)) {
if (provider != null) {
List<String> providerNonIndexableKeys = provider.getNonIndexableKeys(sir.context);
if (providerNonIndexableKeys != null && providerNonIndexableKeys.size() > 0) {
nonIndexableKeys.addAll(providerNonIndexableKeys);
}
}
indexFromLocalProvider(mContext, database, localeStr, provider, sir.className, indexFromLocalProvider(mContext, database, localeStr, provider, sir.className,
sir.iconResId, sir.rank, sir.enabled); sir.iconResId, sir.rank, sir.enabled, nonIndexableKeys);
} }
} }
private Indexable.SearchIndexProvider getSearchIndexProvider(String className) {
try {
final Class<?> clazz = Class.forName(className);
if (Indexable.class.isAssignableFrom(clazz)) {
final Field f = clazz.getField(FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER);
return (Indexable.SearchIndexProvider) f.get(null);
}
} catch (ClassNotFoundException e) {
Log.e(LOG_TAG, "Cannot find class: " + className, e);
} catch (NoSuchFieldException e) {
Log.e(LOG_TAG, "Cannot find field '" + FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'", e);
} catch (IllegalAccessException e) {
Log.e(LOG_TAG,
"Illegal access to field '" + FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'", e);
}
return null;
}
private void indexFromResource(Context context, SQLiteDatabase database, String localeStr, private void indexFromResource(Context context, SQLiteDatabase database, String localeStr,
int xmlResId, String fragmentName, int iconResId, int rank, int xmlResId, String fragmentName, int iconResId, int rank,
String intentAction, String intentTargetPackage, String intentTargetClass, String intentAction, String intentTargetPackage, String intentTargetClass,
List<String> doNotIndexKeys) { List<String> nonIndexableKeys) {
XmlResourceParser parser = null; XmlResourceParser parser = null;
try { try {
@@ -593,7 +708,7 @@ public class Index {
// Insert rows for the main PreferenceScreen node. Rewrite the data for removing // Insert rows for the main PreferenceScreen node. Rewrite the data for removing
// hyphens. // hyphens.
if (!doNotIndexKeys.contains(key)) { if (!nonIndexableKeys.contains(key)) {
title = getDataTitle(context, attrs); title = getDataTitle(context, attrs);
summary = getDataSummary(context, attrs); summary = getDataSummary(context, attrs);
keywords = getDataKeywords(context, attrs); keywords = getDataKeywords(context, attrs);
@@ -612,7 +727,7 @@ public class Index {
nodeName = parser.getName(); nodeName = parser.getName();
key = getDataKey(context, attrs); key = getDataKey(context, attrs);
if (doNotIndexKeys.contains(key)) { if (nonIndexableKeys.contains(key)) {
continue; continue;
} }
@@ -653,58 +768,15 @@ public class Index {
} }
} }
private void indexOneRaw(SQLiteDatabase database, String localeStr,
SearchIndexableRaw raw) {
// Should be the same locale as the one we are processing
if (!raw.locale.toString().equalsIgnoreCase(localeStr)) {
return;
}
updateOneRowWithFilteredData(database, localeStr,
raw.title,
raw.summaryOn,
raw.summaryOff,
raw.entries,
raw.className,
raw.screenTitle,
raw.iconResId,
raw.rank,
raw.keywords,
raw.intentAction,
raw.intentTargetPackage,
raw.intentTargetClass,
raw.enabled,
raw.key);
}
private Indexable.SearchIndexProvider getSearchIndexProvider(String className) {
try {
final Class<?> clazz = Class.forName(className);
if (Indexable.class.isAssignableFrom(clazz)) {
final Field f = clazz.getField(FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER);
return (Indexable.SearchIndexProvider) f.get(null);
}
} catch (ClassNotFoundException e) {
Log.e(LOG_TAG, "Cannot find class: " + className, e);
} catch (NoSuchFieldException e) {
Log.e(LOG_TAG, "Cannot find field '" + FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'", e);
} catch (IllegalAccessException e) {
Log.e(LOG_TAG,
"Illegal access to field '" + FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'", e);
}
return null;
}
private void indexFromLocalProvider(Context context, SQLiteDatabase database, String localeStr, private void indexFromLocalProvider(Context context, SQLiteDatabase database, String localeStr,
Indexable.SearchIndexProvider provider, String className, int iconResId, int rank, Indexable.SearchIndexProvider provider, String className, int iconResId, int rank,
boolean enabled) { boolean enabled, List<String> nonIndexableKeys) {
if (provider == null) { if (provider == null) {
Log.w(LOG_TAG, "Cannot find provider: " + className); Log.w(LOG_TAG, "Cannot find provider: " + className);
return; return;
} }
final List<String> doNotIndexKeys = provider.getNonIndexableKeys(context);
final List<SearchIndexableRaw> rawList = provider.getRawDataToIndex(context, enabled); final List<SearchIndexableRaw> rawList = provider.getRawDataToIndex(context, enabled);
if (rawList != null) { if (rawList != null) {
@@ -717,7 +789,7 @@ public class Index {
continue; continue;
} }
if (doNotIndexKeys.contains(raw.key)) { if (nonIndexableKeys.contains(raw.key)) {
continue; continue;
} }
@@ -759,7 +831,7 @@ public class Index {
indexFromResource(context, database, localeStr, indexFromResource(context, database, localeStr,
item.xmlResId, itemClassName, itemIconResId, itemRank, item.xmlResId, itemClassName, itemIconResId, itemRank,
item.intentAction, item.intentTargetPackage, item.intentAction, item.intentTargetPackage,
item.intentTargetClass, doNotIndexKeys); item.intentTargetClass, nonIndexableKeys);
} }
} }
} }
@@ -951,14 +1023,18 @@ public class Index {
final List<SearchIndexableData> dataToUpdate = params[0].dataToUpdate; final List<SearchIndexableData> dataToUpdate = params[0].dataToUpdate;
final List<String> dataToDelete = params[0].dataToDelete; final List<String> dataToDelete = params[0].dataToDelete;
final Map<String, List<String>> nonIndexableKeys = params[0].nonIndexableKeys;
final boolean forceUpdate = params[0].forceUpdate; final boolean forceUpdate = params[0].forceUpdate;
final SQLiteDatabase database = getWritableDatabase(); final SQLiteDatabase database = getWritableDatabase();
final String localeStr = Locale.getDefault().toString(); final String localeStr = Locale.getDefault().toString();
try { try {
database.beginTransaction(); database.beginTransaction();
if (dataToUpdate.size() > 0) { if (dataToUpdate.size() > 0) {
processDataToUpdate(database, localeStr, dataToUpdate, forceUpdate); processDataToUpdate(database, localeStr, dataToUpdate, nonIndexableKeys,
forceUpdate);
} }
if (dataToDelete.size() > 0) { if (dataToDelete.size() > 0) {
processDataToDelete(database, localeStr, dataToDelete); processDataToDelete(database, localeStr, dataToDelete);
@@ -972,7 +1048,8 @@ public class Index {
} }
private boolean processDataToUpdate(SQLiteDatabase database, String localeStr, private boolean processDataToUpdate(SQLiteDatabase database, String localeStr,
List<SearchIndexableData> dataToUpdate, boolean forceUpdate) { List<SearchIndexableData> dataToUpdate, Map<String, List<String>> nonIndexableKeys,
boolean forceUpdate) {
if (!forceUpdate && isLocaleAlreadyIndexed(database, localeStr)) { if (!forceUpdate && isLocaleAlreadyIndexed(database, localeStr)) {
Log.d(LOG_TAG, "Locale '" + localeStr + "' is already indexed"); Log.d(LOG_TAG, "Locale '" + localeStr + "' is already indexed");
@@ -985,7 +1062,7 @@ public class Index {
final int count = dataToUpdate.size(); final int count = dataToUpdate.size();
for (int n = 0; n < count; n++) { for (int n = 0; n < count; n++) {
final SearchIndexableData data = dataToUpdate.get(n); final SearchIndexableData data = dataToUpdate.get(n);
indexOneSearchIndexableData(database, localeStr, data); indexOneSearchIndexableData(database, localeStr, data, nonIndexableKeys);
} }
final long now = System.currentTimeMillis(); final long now = System.currentTimeMillis();

View File

@@ -33,6 +33,7 @@ import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INT
import static android.provider.SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS; import static android.provider.SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS;
import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS; import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS;
import static android.provider.SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS;
public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider {
private static final String TAG = "SettingsSearchIndexablesProvider"; private static final String TAG = "SettingsSearchIndexablesProvider";
@@ -65,4 +66,10 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider {
Cursor result = new MatrixCursor(INDEXABLES_RAW_COLUMNS); Cursor result = new MatrixCursor(INDEXABLES_RAW_COLUMNS);
return result; return result;
} }
@Override
public Cursor queryNonIndexableKeys(String[] projection) {
MatrixCursor cursor = new MatrixCursor(NON_INDEXABLES_KEYS_COLUMNS);
return cursor;
}
} }