summaryrefslogtreecommitdiffstats
path: root/src/com/android/settings/search/Index.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/settings/search/Index.java')
-rw-r--r--src/com/android/settings/search/Index.java681
1 files changed, 433 insertions, 248 deletions
diff --git a/src/com/android/settings/search/Index.java b/src/com/android/settings/search/Index.java
index 987539b..6f91981 100644
--- a/src/com/android/settings/search/Index.java
+++ b/src/com/android/settings/search/Index.java
@@ -20,6 +20,8 @@ import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.TypedArray;
@@ -44,11 +46,37 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.concurrent.ExecutionException;
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_TITLE;
+import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SUMMARY_ON;
+import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SUMMARY_OFF;
+import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_ENTRIES;
+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_CLASS_NAME;
+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_PACKAGE;
+import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_INTENT_TARGET_CLASS;
+import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_KEY;
+
+import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RANK;
+import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RESID;
+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;
+import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE;
+import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS;
+
import static com.android.settings.search.IndexDatabaseHelper.Tables;
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns;
@@ -57,20 +85,22 @@ public class Index {
private static final String LOG_TAG = "Index";
// Those indices should match the indices of SELECT_COLUMNS !
+ public static final int COLUMN_INDEX_RANK = 0;
public static final int COLUMN_INDEX_TITLE = 1;
public static final int COLUMN_INDEX_SUMMARY_ON = 2;
public static final int COLUMN_INDEX_SUMMARY_OFF = 3;
public static final int COLUMN_INDEX_ENTRIES = 4;
- public static final int COLUMN_INDEX_SWITCH_ON = 5;
- public static final int COLUMN_INDEX_SWITCH_OFF = 6;
- public static final int COLUMN_INDEX_KEYWORDS = 7;
- public static final int COLUMN_INDEX_CLASS_NAME = 8;
- public static final int COLUMN_INDEX_SCREEN_TITLE = 9;
- public static final int COLUMN_INDEX_ICON = 10;
- public static final int COLUMN_INDEX_INTENT_ACTION = 11;
- public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 12;
- public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 13;
- public static final int COLUMN_INDEX_ENABLED = 14;
+ public static final int COLUMN_INDEX_KEYWORDS = 5;
+ public static final int COLUMN_INDEX_CLASS_NAME = 6;
+ public static final int COLUMN_INDEX_SCREEN_TITLE = 7;
+ public static final int COLUMN_INDEX_ICON = 8;
+ public static final int COLUMN_INDEX_INTENT_ACTION = 9;
+ public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 10;
+ public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 11;
+ public static final int COLUMN_INDEX_ENABLED = 12;
+ public static final int COLUMN_INDEX_KEY = 13;
+
+ public static final String ENTRIES_SEPARATOR = "|";
// If you change the order of columns here, you SHOULD change the COLUMN_INDEX_XXX values
private static final String[] SELECT_COLUMNS = new String[] {
@@ -79,15 +109,15 @@ public class Index {
IndexColumns.DATA_SUMMARY_ON, // 2
IndexColumns.DATA_SUMMARY_OFF, // 3
IndexColumns.DATA_ENTRIES, // 4
- IndexColumns.DATA_SWITCH_ON, // 5
- IndexColumns.DATA_SWITCH_OFF, // 6
- IndexColumns.DATA_KEYWORDS, // 7
- IndexColumns.CLASS_NAME, // 8
- IndexColumns.SCREEN_TITLE, // 9
- IndexColumns.ICON, // 10
- IndexColumns.INTENT_ACTION, // 11
- IndexColumns.INTENT_TARGET_PACKAGE, // 12
- IndexColumns.INTENT_TARGET_CLASS // 13
+ IndexColumns.DATA_KEYWORDS, // 5
+ IndexColumns.CLASS_NAME, // 6
+ IndexColumns.SCREEN_TITLE, // 7
+ IndexColumns.ICON, // 8
+ IndexColumns.INTENT_ACTION, // 9
+ IndexColumns.INTENT_TARGET_PACKAGE, // 10
+ IndexColumns.INTENT_TARGET_CLASS, // 11
+ IndexColumns.ENABLED, // 12
+ IndexColumns.DATA_KEY_REF // 13
};
private static final String[] MATCH_COLUMNS = {
@@ -97,10 +127,6 @@ public class Index {
IndexColumns.DATA_SUMMARY_ON_NORMALIZED,
IndexColumns.DATA_SUMMARY_OFF,
IndexColumns.DATA_SUMMARY_OFF_NORMALIZED,
- IndexColumns.DATA_SWITCH_ON,
- IndexColumns.DATA_SWITCH_ON_NORMALIZED,
- IndexColumns.DATA_SWITCH_OFF,
- IndexColumns.DATA_SWITCH_OFF_NORMALIZED,
IndexColumns.DATA_ENTRIES,
IndexColumns.DATA_KEYWORDS
};
@@ -115,7 +141,8 @@ public class Index {
private static final String NODE_NAME_PREFERENCE_SCREEN = "PreferenceScreen";
private static final String NODE_NAME_CHECK_BOX_PREFERENCE = "CheckBoxPreference";
private static final String NODE_NAME_LIST_PREFERENCE = "ListPreference";
- private static final String NODE_NAME_SWITCH_PREFERENCE = "SwitchPreference";
+
+ private static final List<String> EMPTY_LIST = Collections.<String>emptyList();
private static Index sInstance;
private final AtomicBoolean mIsAvailable = new AtomicBoolean(false);
@@ -127,17 +154,21 @@ public class Index {
*/
private class UpdateData {
public List<SearchIndexableData> dataToUpdate;
- public List<String> dataToDelete;
+ public List<SearchIndexableData> dataToDelete;
+ public Map<String, List<String>> nonIndexableKeys;
+
public boolean forceUpdate = false;
public UpdateData() {
dataToUpdate = new ArrayList<SearchIndexableData>();
- dataToDelete = new ArrayList<String>();
+ dataToDelete = new ArrayList<SearchIndexableData>();
+ nonIndexableKeys = new HashMap<String, List<String>>();
}
public void clear() {
dataToUpdate.clear();
dataToDelete.clear();
+ nonIndexableKeys.clear();
forceUpdate = false;
}
}
@@ -172,6 +203,94 @@ public class Index {
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) {
synchronized (mDataToProcess) {
mDataToProcess.dataToUpdate.add(data);
@@ -187,29 +306,55 @@ public class Index {
}
}
- public void deleteIndexableData(String[] array) {
+ public void deleteIndexableData(SearchIndexableData data) {
synchronized (mDataToProcess) {
- final int count = array.length;
- for (int n = 0; n < count; n++) {
- mDataToProcess.dataToDelete.add(array[n]);
- }
+ mDataToProcess.dataToDelete.add(data);
}
}
- public boolean update() {
- final Intent intent = new Intent(SearchIndexablesContract.PROVIDER_INTERFACE);
- List<ResolveInfo> list =
- mContext.getPackageManager().queryIntentContentProviders(intent, 0);
+ public void addNonIndexableKeys(String authority, List<String> keys) {
+ synchronized (mDataToProcess) {
+ mDataToProcess.nonIndexableKeys.put(authority, keys);
+ }
+ }
- final int size = list.size();
- for (int n = 0; n < size; n++) {
- final ResolveInfo info = list.get(n);
- final String authority = info.providerInfo.authority;
- final String packageName = info.providerInfo.packageName;
- addIndexablesFromRemoteProvider(packageName, authority);
+ /**
+ * Only allow a "well known" SearchIndexablesProvider. The provider should:
+ *
+ * - have read/write {@link android.Manifest.permission#READ_SEARCH_INDEXABLES}
+ * - be from a privileged package
+ */
+ private boolean isWellKnownProvider(ResolveInfo info) {
+ final String authority = info.providerInfo.authority;
+ final String packageName = info.providerInfo.applicationInfo.packageName;
+
+ if (TextUtils.isEmpty(authority) || TextUtils.isEmpty(packageName)) {
+ return false;
}
- return updateInternal();
+ final String readPermission = info.providerInfo.readPermission;
+ final String writePermission = info.providerInfo.writePermission;
+
+ if (TextUtils.isEmpty(readPermission) || TextUtils.isEmpty(writePermission)) {
+ return false;
+ }
+
+ if (!android.Manifest.permission.READ_SEARCH_INDEXABLES.equals(readPermission) ||
+ !android.Manifest.permission.READ_SEARCH_INDEXABLES.equals(writePermission)) {
+ return false;
+ }
+
+ return isPrivilegedPackage(packageName);
+ }
+
+ private boolean isPrivilegedPackage(String packageName) {
+ final PackageManager pm = mContext.getPackageManager();
+ try {
+ PackageInfo packInfo = pm.getPackageInfo(packageName, 0);
+ return ((packInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
}
public boolean updateFromRemoteProvider(String packageName, String authority) {
@@ -219,7 +364,17 @@ public class Index {
return updateInternal();
}
- public boolean updateFromClassNameResource(String className, boolean includeInSearchResults) {
+ /**
+ * Update the Index for a specific class name resources
+ *
+ * @param className the class name (typically a fragment name).
+ * @param rebuild true means that you want to delete the data from the Index first.
+ * @param includeInSearchResults true means that you want the bit "enabled" set so that the
+ * data will be seen included into the search results
+ * @return true of the Index update has been successful.
+ */
+ public boolean updateFromClassNameResource(String className, boolean rebuild,
+ boolean includeInSearchResults) {
if (className == null) {
throw new IllegalArgumentException("class name cannot be null!");
}
@@ -229,6 +384,9 @@ public class Index {
return false;
}
res.enabled = includeInSearchResults;
+ if (rebuild) {
+ deleteIndexableData(res);
+ }
addIndexableData(res);
mDataToProcess.forceUpdate = true;
boolean result = updateInternal();
@@ -236,8 +394,9 @@ public class Index {
return result;
}
- private boolean updateFromSearchIndexableData(SearchIndexableData data) {
+ public boolean updateFromSearchIndexableData(SearchIndexableData data) {
addIndexableData(data);
+ mDataToProcess.forceUpdate = true;
return updateInternal();
}
@@ -249,26 +408,6 @@ public class Index {
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) {
return Uri.parse("content://" + authority + "/" +
SearchIndexablesContract.INDEXABLES_XML_RES_PATH);
@@ -279,6 +418,11 @@ public class Index {
SearchIndexablesContract.INDEXABLES_RAW_PATH);
}
+ private static Uri buildUriForNonIndexableKeys(String authority) {
+ return Uri.parse("content://" + authority + "/" +
+ SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH);
+ }
+
private boolean updateInternal() {
synchronized (mDataToProcess) {
final UpdateIndexTask task = new UpdateIndexTask();
@@ -301,8 +445,7 @@ public class Index {
Uri uri, String[] projection) {
final ContentResolver resolver = packageContext.getContentResolver();
- final Cursor cursor = resolver.query(uri, projection,
- null, null, null);
+ 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());
@@ -313,15 +456,17 @@ public class Index {
final int count = cursor.getCount();
if (count > 0) {
while (cursor.moveToNext()) {
- final int rank = cursor.getInt(0);
- final int xmlResId = cursor.getInt(1);
+ final int rank = cursor.getInt(COLUMN_INDEX_XML_RES_RANK);
+ final int xmlResId = cursor.getInt(COLUMN_INDEX_XML_RES_RESID);
- final String className = cursor.getString(2);
- final int iconResId = cursor.getInt(3);
+ final String className = cursor.getString(COLUMN_INDEX_XML_RES_CLASS_NAME);
+ final int iconResId = cursor.getInt(COLUMN_INDEX_XML_RES_ICON_RESID);
- final String action = cursor.getString(4);
- final String targetPackage = cursor.getString(5);
- final String targetClass = cursor.getString(6);
+ final String action = cursor.getString(COLUMN_INDEX_XML_RES_INTENT_ACTION);
+ final String targetPackage = cursor.getString(
+ COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE);
+ final String targetClass = cursor.getString(
+ COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS);
SearchIndexableResource sir = new SearchIndexableResource(packageContext);
sir.rank = rank;
@@ -345,8 +490,7 @@ public class Index {
Uri uri, String[] projection) {
final ContentResolver resolver = packageContext.getContentResolver();
- final Cursor cursor = resolver.query(uri, projection,
- null, null, null);
+ 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());
@@ -357,23 +501,25 @@ public class Index {
final int count = cursor.getCount();
if (count > 0) {
while (cursor.moveToNext()) {
- final int rank = cursor.getInt(0);
- final String title = cursor.getString(1);
- final String summaryOn = cursor.getString(2);
- final String summaryOff = cursor.getString(3);
- final String entries = cursor.getString(4);
- final String switchOn = cursor.getString(5);
- final String switchOff = cursor.getString(6);
- final String keywords = cursor.getString(7);
+ final int rank = cursor.getInt(COLUMN_INDEX_RAW_RANK);
+ final String title = cursor.getString(COLUMN_INDEX_RAW_TITLE);
+ final String summaryOn = cursor.getString(COLUMN_INDEX_RAW_SUMMARY_ON);
+ final String summaryOff = cursor.getString(COLUMN_INDEX_RAW_SUMMARY_OFF);
+ final String entries = cursor.getString(COLUMN_INDEX_RAW_ENTRIES);
+ final String keywords = cursor.getString(COLUMN_INDEX_RAW_KEYWORDS);
- final String screenTitle = cursor.getString(8);
+ final String screenTitle = cursor.getString(COLUMN_INDEX_RAW_SCREEN_TITLE);
- final String className = cursor.getString(9);
- final int iconResId = cursor.getInt(10);
+ final String className = cursor.getString(COLUMN_INDEX_RAW_CLASS_NAME);
+ final int iconResId = cursor.getInt(COLUMN_INDEX_RAW_ICON_RESID);
- final String action = cursor.getString(11);
- final String targetPackage = cursor.getString(12);
- final String targetClass = cursor.getString(13);
+ final String action = cursor.getString(COLUMN_INDEX_RAW_INTENT_ACTION);
+ final String targetPackage = cursor.getString(
+ COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE);
+ final String targetClass = cursor.getString(
+ COLUMN_INDEX_RAW_INTENT_TARGET_CLASS);
+
+ final String key = cursor.getString(COLUMN_INDEX_RAW_KEY);
SearchIndexableRaw data = new SearchIndexableRaw(packageContext);
data.rank = rank;
@@ -381,8 +527,6 @@ public class Index {
data.summaryOn = summaryOn;
data.summaryOff = summaryOff;
data.entries = entries;
- data.switchOn = switchOn;
- data.switchOff = switchOff;
data.keywords = keywords;
data.screenTitle = screenTitle;
data.className = className;
@@ -391,6 +535,7 @@ public class Index {
data.intentAction = action;
data.intentTargetPackage = targetPackage;
data.intentTargetClass = targetClass;
+ data.key = key;
addIndexableData(data);
}
@@ -455,29 +600,95 @@ public class Index {
}
private void indexOneSearchIndexableData(SQLiteDatabase database, String localeStr,
- SearchIndexableData data) {
+ SearchIndexableData data, Map<String, List<String>> nonIndexableKeys) {
if (data instanceof SearchIndexableResource) {
- indexOneResource(database, localeStr, (SearchIndexableResource) data);
+ indexOneResource(database, localeStr, (SearchIndexableResource) data, nonIndexableKeys);
} else if (data instanceof SearchIndexableRaw) {
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,
- SearchIndexableResource sir) {
- if (sir.xmlResId > 0) {
+ SearchIndexableResource sir, Map<String, List<String>> nonIndexableKeysFromResource) {
+
+ if (sir == null) {
+ Log.e(LOG_TAG, "Cannot index a null resource!");
+ return;
+ }
+
+ // Will be non null only for a Local provider
+ final Indexable.SearchIndexProvider provider =
+ TextUtils.isEmpty(sir.className) ? null : getSearchIndexProvider(sir.className);
+
+ List<String> nonIndexableKeys = new ArrayList<String>();
+
+ if (sir.xmlResId > SearchIndexableResources.NO_DATA_RES_ID) {
+ List<String> resNonIndxableKeys = nonIndexableKeysFromResource.get(sir.packageName);
+ if (resNonIndxableKeys != null && resNonIndxableKeys.size() > 0) {
+ nonIndexableKeys.addAll(resNonIndxableKeys);
+ }
indexFromResource(sir.context, database, localeStr,
sir.xmlResId, sir.className, sir.iconResId, sir.rank,
- sir.intentAction, sir.intentTargetPackage, sir.intentTargetClass);
+ sir.intentAction, sir.intentTargetPackage, sir.intentTargetClass,
+ nonIndexableKeys);
} else if (!TextUtils.isEmpty(sir.className)) {
- sir.context = mContext;
- indexFromLocalProvider(database, localeStr, sir);
+ 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,
+ 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,
- int xmlResId, String fragmentName, int iconResId, int rank,
- String intentAction, String intentTargetPackage, String intentTargetClass) {
+ int xmlResId, String fragmentName, int iconResId, int rank,
+ String intentAction, String intentTargetPackage, String intentTargetClass,
+ List<String> nonIndexableKeys) {
XmlResourceParser parser = null;
try {
@@ -498,17 +709,26 @@ public class Index {
final int outerDepth = parser.getDepth();
final AttributeSet attrs = Xml.asAttributeSet(parser);
+
final String screenTitle = getDataTitle(context, attrs);
- String title = getDataTitle(context, attrs);
- String summary = getDataSummary(context, attrs);
- String keywords = getDataKeywords(context, attrs);
+ String key = getDataKey(context, attrs);
+
+ String title;
+ String summary;
+ String keywords;
// Insert rows for the main PreferenceScreen node. Rewrite the data for removing
// hyphens.
- updateOneRowWithFilteredData(database, localeStr, title, summary, null, null,
- null, null, fragmentName, screenTitle, iconResId, rank, keywords,
- intentAction, intentTargetPackage, intentTargetClass, true);
+ if (!nonIndexableKeys.contains(key)) {
+ title = getDataTitle(context, attrs);
+ summary = getDataSummary(context, attrs);
+ keywords = getDataKeywords(context, attrs);
+
+ updateOneRowWithFilteredData(database, localeStr, title, summary, null, null,
+ fragmentName, screenTitle, iconResId, rank,
+ keywords, intentAction, intentTargetPackage, intentTargetClass, true, key);
+ }
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
@@ -518,6 +738,11 @@ public class Index {
nodeName = parser.getName();
+ key = getDataKey(context, attrs);
+ if (nonIndexableKeys.contains(key)) {
+ continue;
+ }
+
title = getDataTitle(context, attrs);
keywords = getDataKeywords(context, attrs);
@@ -525,27 +750,24 @@ public class Index {
summary = getDataSummary(context, attrs);
String entries = null;
- String switchOn = null;
- String switchOff = null;
if (nodeName.endsWith(NODE_NAME_LIST_PREFERENCE)) {
entries = getDataEntries(context, attrs);
- } else if (nodeName.endsWith(NODE_NAME_SWITCH_PREFERENCE)) {
- switchOn = getDataSwitchOn(context, attrs);
- switchOff = getDataSwitchOff(context, attrs);
}
// Insert rows for the child nodes of PreferenceScreen
updateOneRowWithFilteredData(database, localeStr, title, summary, null, entries,
- switchOn, switchOff, fragmentName, screenTitle, iconResId, rank, keywords,
- intentAction, intentTargetPackage, intentTargetClass, true);
- } else if (nodeName.equals(NODE_NAME_CHECK_BOX_PREFERENCE)) {
+ fragmentName, screenTitle, iconResId, rank,
+ keywords, intentAction, intentTargetPackage, intentTargetClass,
+ true, key);
+ } else {
final String summaryOn = getDataSummaryOn(context, attrs);
final String summaryOff = getDataSummaryOff(context, attrs);
updateOneRowWithFilteredData(database, localeStr, title, summaryOn, summaryOff,
- null, null, null, fragmentName, screenTitle, iconResId, rank, keywords,
- intentAction, intentTargetPackage, intentTargetClass, true);
+ null, fragmentName, screenTitle, iconResId, rank,
+ keywords, intentAction, intentTargetPackage, intentTargetClass,
+ true, key);
}
}
@@ -558,106 +780,80 @@ 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)) {
+ private void indexFromLocalProvider(Context context, SQLiteDatabase database, String localeStr,
+ Indexable.SearchIndexProvider provider, String className, int iconResId, int rank,
+ boolean enabled, List<String> nonIndexableKeys) {
+
+ if (provider == null) {
+ Log.w(LOG_TAG, "Cannot find provider: " + className);
return;
}
- updateOneRowWithFilteredData(database, localeStr,
- raw.title,
- raw.summaryOn,
- raw.summaryOff,
- raw.entries,
- raw.switchOn,
- raw.switchOff,
- raw.className,
- raw.screenTitle,
- raw.iconResId,
- raw.rank,
- raw.keywords,
- raw.intentAction,
- raw.intentTargetPackage,
- raw.intentTargetClass,
- raw.enabled);
- }
+ final List<SearchIndexableRaw> rawList = provider.getRawDataToIndex(context, enabled);
- private void indexFromLocalProvider(SQLiteDatabase database, String localeStr,
- SearchIndexableResource sir) {
- try {
- final Class<?> clazz = Class.forName(sir.className);
- if (Indexable.class.isAssignableFrom(clazz)) {
- final Field f = clazz.getField(FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER);
- final Indexable.SearchIndexProvider provider =
- (Indexable.SearchIndexProvider) f.get(null);
-
- final List<SearchIndexableRaw> rawList =
- provider.getRawDataToIndex(sir.context, sir.enabled);
- if (rawList != null) {
- final int rawSize = rawList.size();
- for (int i = 0; i < rawSize; i++) {
- SearchIndexableRaw raw = rawList.get(i);
-
- // Should be the same locale as the one we are processing
- if (!raw.locale.toString().equalsIgnoreCase(localeStr)) {
- continue;
- }
+ if (rawList != null) {
+ final int rawSize = rawList.size();
+ for (int i = 0; i < rawSize; i++) {
+ SearchIndexableRaw raw = rawList.get(i);
- updateOneRowWithFilteredData(database, localeStr,
- raw.title,
- raw.summaryOn,
- raw.summaryOff,
- raw.entries,
- raw.switchOn,
- raw.switchOff,
- sir.className,
- raw.screenTitle,
- sir.iconResId,
- sir.rank,
- raw.keywords,
- raw.intentAction,
- raw.intentTargetPackage,
- raw.intentTargetClass,
- raw.enabled);
- }
+ // Should be the same locale as the one we are processing
+ if (!raw.locale.toString().equalsIgnoreCase(localeStr)) {
+ continue;
}
- final List<SearchIndexableResource> resList =
- provider.getXmlResourcesToIndex(sir.context, sir.enabled);
- if (resList != null) {
- final int resSize = resList.size();
- for (int i = 0; i < resSize; i++) {
- SearchIndexableResource item = resList.get(i);
+ if (nonIndexableKeys.contains(raw.key)) {
+ continue;
+ }
- // Should be the same locale as the one we are processing
- if (!item.locale.toString().equalsIgnoreCase(localeStr)) {
- continue;
- }
+ updateOneRowWithFilteredData(database, localeStr,
+ raw.title,
+ raw.summaryOn,
+ raw.summaryOff,
+ raw.entries,
+ className,
+ raw.screenTitle,
+ iconResId,
+ rank,
+ raw.keywords,
+ raw.intentAction,
+ raw.intentTargetPackage,
+ raw.intentTargetClass,
+ raw.enabled,
+ raw.key);
+ }
+ }
- indexFromResource(sir.context, database, localeStr,
- item.xmlResId, item.className, item.iconResId, item.rank,
- item.intentAction, item.intentTargetPackage,
- item.intentTargetClass);
- }
+ final List<SearchIndexableResource> resList =
+ provider.getXmlResourcesToIndex(context, enabled);
+ if (resList != null) {
+ final int resSize = resList.size();
+ for (int i = 0; i < resSize; i++) {
+ SearchIndexableResource item = resList.get(i);
+
+ // Should be the same locale as the one we are processing
+ if (!item.locale.toString().equalsIgnoreCase(localeStr)) {
+ continue;
}
+
+ final int itemIconResId = (item.iconResId == 0) ? iconResId : item.iconResId;
+ final int itemRank = (item.rank == 0) ? rank : item.rank;
+ String itemClassName = (TextUtils.isEmpty(item.className))
+ ? className : item.className;
+
+ indexFromResource(context, database, localeStr,
+ item.xmlResId, itemClassName, itemIconResId, itemRank,
+ item.intentAction, item.intentTargetPackage,
+ item.intentTargetClass, nonIndexableKeys);
}
- } catch (ClassNotFoundException e) {
- Log.e(LOG_TAG, "Cannot find class: " + sir.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);
}
}
private void updateOneRowWithFilteredData(SQLiteDatabase database, String locale,
String title, String summaryOn, String summaryOff, String entries,
- String switchOn, String switchOff, String className,
+ String className,
String screenTitle, int iconResId, int rank, String keywords,
String intentAction, String intentTargetPackage, String intentTargetClass,
- boolean enabled) {
+ boolean enabled, String key) {
String updatedTitle;
if (title != null) {
@@ -681,43 +877,24 @@ public class Index {
updatedSummaryOff = EMPTY;
}
- String updatedSwitchOn;
- if (switchOn != null) {
- updatedSwitchOn = switchOn.replaceAll(NON_BREAKING_HYPHEN, HYPHEN);
- } else {
- updatedSwitchOn = EMPTY;
- }
-
- String updatedSwitchOff;
- if (switchOff != null) {
- updatedSwitchOff = switchOff.replaceAll(NON_BREAKING_HYPHEN, HYPHEN);
- } else {
- updatedSwitchOff = EMPTY;
- }
-
String normalizedTitle = updatedTitle.replaceAll(HYPHEN, EMPTY);
String normalizedSummaryOn = updatedSummaryOn.replaceAll(HYPHEN, EMPTY);
String normalizedSummaryOff = updatedSummaryOff.replaceAll(HYPHEN, EMPTY);
- String normalizedSwitchOn = updatedSwitchOn.replaceAll(HYPHEN, EMPTY);
- String normalizedSwitchOff = updatedSwitchOff.replaceAll(HYPHEN, EMPTY);
updateOneRow(database, locale,
updatedTitle, normalizedTitle, updatedSummaryOn, normalizedSummaryOn,
updatedSummaryOff, normalizedSummaryOff, entries,
- updatedSwitchOn, normalizedSwitchOn, updatedSwitchOff, normalizedSwitchOff,
className, screenTitle, iconResId,
- rank, keywords, intentAction, intentTargetPackage, intentTargetClass, enabled);
+ rank, keywords, intentAction, intentTargetPackage, intentTargetClass, enabled, key);
}
private void updateOneRow(SQLiteDatabase database, String locale,
String updatedTitle, String normalizedTitle,
String updatedSummaryOn, String normalizedSummaryOn,
String updatedSummaryOff, String normalizedSummaryOff, String entries,
- String updatedSwitchOn, String normalizedSwitchOn,
- String updatedSwitchOff, String normalizedSwitchOff,
String className, String screenTitle, int iconResId, int rank, String keywords,
String intentAction, String intentTargetPackage, String intentTargetClass,
- boolean enabled) {
+ boolean enabled, String key) {
if (TextUtils.isEmpty(updatedTitle)) {
return;
@@ -734,10 +911,6 @@ public class Index {
values.put(IndexColumns.DATA_SUMMARY_OFF, updatedSummaryOff);
values.put(IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, normalizedSummaryOff);
values.put(IndexColumns.DATA_ENTRIES, entries);
- values.put(IndexColumns.DATA_SWITCH_ON, updatedSwitchOn);
- values.put(IndexColumns.DATA_SWITCH_ON_NORMALIZED, normalizedSwitchOn);
- values.put(IndexColumns.DATA_SWITCH_OFF, updatedSwitchOff);
- values.put(IndexColumns.DATA_SWITCH_OFF_NORMALIZED, normalizedSwitchOff);
values.put(IndexColumns.DATA_KEYWORDS, keywords);
values.put(IndexColumns.CLASS_NAME, className);
values.put(IndexColumns.SCREEN_TITLE, screenTitle);
@@ -746,10 +919,17 @@ public class Index {
values.put(IndexColumns.INTENT_TARGET_CLASS, intentTargetClass);
values.put(IndexColumns.ICON, iconResId);
values.put(IndexColumns.ENABLED, enabled);
+ values.put(IndexColumns.DATA_KEY_REF, key);
database.replaceOrThrow(Tables.TABLE_PREFS_INDEX, null, values);
}
+ private String getDataKey(Context context, AttributeSet attrs) {
+ return getData(context, attrs,
+ com.android.internal.R.styleable.Preference,
+ com.android.internal.R.styleable.Preference_key);
+ }
+
private String getDataTitle(Context context, AttributeSet attrs) {
return getData(context, attrs,
com.android.internal.R.styleable.Preference,
@@ -780,18 +960,6 @@ public class Index {
com.android.internal.R.styleable.ListPreference_entries);
}
- private String getDataSwitchOn(Context context, AttributeSet attrs) {
- return getData(context, attrs,
- com.android.internal.R.styleable.SwitchPreference,
- com.android.internal.R.styleable.SwitchPreference_switchTextOn);
- }
-
- private String getDataSwitchOff(Context context, AttributeSet attrs) {
- return getData(context, attrs,
- com.android.internal.R.styleable.SwitchPreference,
- com.android.internal.R.styleable.SwitchPreference_switchTextOff);
- }
-
private String getDataKeywords(Context context, AttributeSet attrs) {
return getData(context, attrs, R.styleable.Preference, R.styleable.Preference_keywords);
}
@@ -828,7 +996,7 @@ public class Index {
final StringBuilder result = new StringBuilder();
for (int n = 0; n < count; n++) {
result.append(data[n]);
- result.append(" ");
+ result.append(ENTRIES_SEPARATOR);
}
return result.toString();
}
@@ -866,19 +1034,23 @@ public class Index {
boolean result = false;
final List<SearchIndexableData> dataToUpdate = params[0].dataToUpdate;
- final List<String> dataToDelete = params[0].dataToDelete;
+ final List<SearchIndexableData> dataToDelete = params[0].dataToDelete;
+ final Map<String, List<String>> nonIndexableKeys = params[0].nonIndexableKeys;
+
final boolean forceUpdate = params[0].forceUpdate;
+
final SQLiteDatabase database = getWritableDatabase();
final String localeStr = Locale.getDefault().toString();
try {
database.beginTransaction();
- if (dataToUpdate.size() > 0) {
- processDataToUpdate(database, localeStr, dataToUpdate, forceUpdate);
- }
if (dataToDelete.size() > 0) {
processDataToDelete(database, localeStr, dataToDelete);
}
+ if (dataToUpdate.size() > 0) {
+ processDataToUpdate(database, localeStr, dataToUpdate, nonIndexableKeys,
+ forceUpdate);
+ }
database.setTransactionSuccessful();
result = true;
} finally {
@@ -888,7 +1060,8 @@ public class Index {
}
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)) {
Log.d(LOG_TAG, "Locale '" + localeStr + "' is already indexed");
@@ -901,7 +1074,7 @@ public class Index {
final int count = dataToUpdate.size();
for (int n = 0; n < count; n++) {
final SearchIndexableData data = dataToUpdate.get(n);
- indexOneSearchIndexableData(database, localeStr, data);
+ indexOneSearchIndexableData(database, localeStr, data, nonIndexableKeys);
}
final long now = System.currentTimeMillis();
@@ -911,15 +1084,27 @@ public class Index {
}
private boolean processDataToDelete(SQLiteDatabase database, String localeStr,
- List<String> dataToDelete) {
+ List<SearchIndexableData> dataToDelete) {
boolean result = false;
final long current = System.currentTimeMillis();
final int count = dataToDelete.size();
for (int n = 0; n < count; n++) {
- final String data = dataToDelete.get(n);
- delete(database, data);
+ final SearchIndexableData data = dataToDelete.get(n);
+ if (data == null) {
+ continue;
+ }
+ if (!TextUtils.isEmpty(data.className)) {
+ delete(database, IndexColumns.CLASS_NAME, data.className);
+ } else {
+ if (data instanceof SearchIndexableRaw) {
+ final SearchIndexableRaw raw = (SearchIndexableRaw) data;
+ if (!TextUtils.isEmpty(raw.title)) {
+ delete(database, IndexColumns.DATA_TITLE, raw.title);
+ }
+ }
+ }
}
final long now = System.currentTimeMillis();
@@ -928,9 +1113,9 @@ public class Index {
return result;
}
- private int delete(SQLiteDatabase database, String title) {
- final String whereClause = IndexColumns.DATA_TITLE + "=?";
- final String[] whereArgs = new String[] { title };
+ private int delete(SQLiteDatabase database, String columName, String value) {
+ final String whereClause = columName + "=?";
+ final String[] whereArgs = new String[] { value };
return database.delete(Tables.TABLE_PREFS_INDEX, whereClause, whereArgs);
}