Add external Preferences indexing
- define SettingsSearchIndexablesProvider as an internal
SearchIndexablesProvider
- protect access thru using android.permission.READ_SEARCH_INDEXABLES
- update WallpaperTypeSettings and WifiSettings for taking care of
the new model
- update the Dashboard for taking care about external Icons for the
search result
- update sqlite model/version for taking care about Intents
(enable launching external applications for showing the settings)
Change-Id: I2e38599327e6480f1754f52666becce0884cee9d
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index e49d827..0e6128c 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -94,14 +94,12 @@
import com.android.settings.deviceinfo.Memory;
import com.android.settings.deviceinfo.UsbSettings;
import com.android.settings.fuelgauge.PowerUsageSummary;
-import com.android.settings.indexer.Index;
-import com.android.settings.indexer.IndexableRef;
+import com.android.settings.search.Index;
import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
import com.android.settings.inputmethod.SpellCheckersSettings;
import com.android.settings.inputmethod.UserDictionaryList;
import com.android.settings.location.LocationSettings;
-import com.android.settings.net.DataUsageMeteredSettings;
import com.android.settings.nfc.AndroidBeam;
import com.android.settings.nfc.PaymentSettings;
import com.android.settings.print.PrintJobSettingsFragment;
@@ -342,76 +340,6 @@
}
};
- private static int NO_DATA_RES_ID = 0;
-
- /**
- * Indexable data description.
- *
- * Known restriction: we are only searching (for now) the first level of Settings.
- */
- private static IndexableRef[] INDEXABLE_REFS = new IndexableRef[] {
- new IndexableRef(1, NO_DATA_RES_ID,
- WifiSettings.class.getName(),
- R.drawable.ic_settings_wireless),
- new IndexableRef(2, R.xml.bluetooth_settings,
- BluetoothSettings.class.getName(),
- R.drawable.ic_settings_bluetooth2),
- new IndexableRef(3, R.xml.data_usage_metered_prefs,
- DataUsageMeteredSettings.class.getName(),
- R.drawable.ic_settings_data_usage),
- new IndexableRef(4, R.xml.wireless_settings,
- WirelessSettings.class.getName(),
- R.drawable.empty_icon),
- new IndexableRef(5, R.xml.home_selection,
- HomeSettings.class.getName(),
- R.drawable.ic_settings_home),
- new IndexableRef(6, R.xml.sound_settings,
- SoundSettings.class.getName(),
- R.drawable.ic_settings_sound),
- new IndexableRef(7, R.xml.display_settings,
- DisplaySettings.class.getName(),
- R.drawable.ic_settings_display),
- new IndexableRef(7, NO_DATA_RES_ID,
- WallpaperTypeSettings.class.getName(),
- R.drawable.ic_settings_display),
- new IndexableRef(8, R.xml.device_info_memory,
- Memory.class.getName(),
- R.drawable.ic_settings_storage),
- new IndexableRef(9, R.xml.power_usage_summary,
- PowerUsageSummary.class.getName(),
- R.drawable.ic_settings_battery),
- new IndexableRef(10, R.xml.user_settings,
- UserSettings.class.getName(),
- R.drawable.ic_settings_multiuser),
- new IndexableRef(11, R.xml.location_settings,
- LocationSettings.class.getName(),
- R.drawable.ic_settings_location),
- new IndexableRef(12, R.xml.security_settings,
- SecuritySettings.class.getName(),
- R.drawable.ic_settings_security),
- new IndexableRef(13, R.xml.language_settings,
- InputMethodAndLanguageSettings.class.getName(),
- R.drawable.ic_settings_language),
- new IndexableRef(14, R.xml.privacy_settings,
- PrivacySettings.class.getName(),
- R.drawable.ic_settings_backup),
- new IndexableRef(15, R.xml.date_time_prefs,
- DateTimeSettings.class.getName(),
- R.drawable.ic_settings_date_time),
- new IndexableRef(16, R.xml.accessibility_settings,
- AccessibilitySettings.class.getName(),
- R.drawable.ic_settings_accessibility),
- new IndexableRef(17, R.xml.print_settings,
- PrintSettingsFragment.class.getName(),
- com.android.internal.R.drawable.ic_print),
- new IndexableRef(18, R.xml.development_prefs,
- DevelopmentSettings.class.getName(),
- R.drawable.ic_settings_development),
- new IndexableRef(19, R.xml.device_info_settings,
- DeviceInfoSettings.class.getName(),
- R.drawable.ic_settings_about),
- };
-
@Override
public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
// Override the fragment title for Wallpaper settings
@@ -552,7 +480,6 @@
getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
}
- Index.getInstance(this).addIndexableData(INDEXABLE_REFS);
Index.getInstance(this).update();
mAuthenticatorHelper = new AuthenticatorHelper();
@@ -914,22 +841,6 @@
}
/**
- * Switch the fragment pane to show the given preference fragment.
- *
- * (used for initial fragment)
- *
- * @param fragmentName The name of the fragment to display.
- * @param args Optional arguments to supply to the fragment.
- * @param validate true means that the fragment's Header needs to be validated.
- * @param title The title of the fragment to display.
- */
- private void switchToHeader(String fragmentName, Bundle args, boolean validate,
- CharSequence title) {
- setSelectedHeader(null);
- switchToHeaderInner(fragmentName, args, validate, false, title);
- }
-
- /**
* Switch to a specific Header with taking care of validation, Title and BackStack
*/
private void switchToHeaderInner(String fragmentName, Bundle args, boolean validate,
diff --git a/src/com/android/settings/WallpaperTypeSettings.java b/src/com/android/settings/WallpaperTypeSettings.java
index f46315a..7dc5e4d 100644
--- a/src/com/android/settings/WallpaperTypeSettings.java
+++ b/src/com/android/settings/WallpaperTypeSettings.java
@@ -24,9 +24,9 @@
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceScreen;
-import com.android.settings.indexer.Indexable;
-import com.android.settings.indexer.IndexableData;
-import com.android.settings.indexer.IndexableRef;
+import android.provider.SearchIndexableResource;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.SearchIndexableRaw;
import java.util.ArrayList;
import java.util.List;
@@ -64,16 +64,16 @@
}
}
- public static final IndexDataProvider INDEX_DATA_PROVIDER =
- new IndexDataProvider() {
+ public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new SearchIndexProvider() {
@Override
- public List<IndexableRef> getRefsToIndex(Context context) {
+ public List<SearchIndexableResource> getXmlResourcesToIndex(Context context) {
return null;
}
@Override
- public List<IndexableData> getRawDataToIndex(Context context) {
- final List<IndexableData> result = new ArrayList<IndexableData>();
+ public List<SearchIndexableRaw> getRawDataToIndex(Context context) {
+ final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
final Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER);
final PackageManager pm = context.getPackageManager();
@@ -82,17 +82,14 @@
// Add indexable data for each of the matching activities
for (ResolveInfo info : rList) {
- Intent prefIntent = new Intent(intent);
- prefIntent.setComponent(new ComponentName(
- info.activityInfo.packageName, info.activityInfo.name));
CharSequence label = info.loadLabel(pm);
if (label == null) label = info.activityInfo.packageName;
- IndexableData data = new IndexableData();
+ SearchIndexableRaw data = new SearchIndexableRaw(context);
data.title = label.toString();
- data.fragmentTitle = context.getResources().getString(
+ data.screenTitle = context.getResources().getString(
R.string.wallpaper_settings_fragment_title);
- data.intentAction = intent.getAction();
+ data.intentAction = Intent.ACTION_SET_WALLPAPER;
data.intentTargetPackage = info.activityInfo.packageName;
data.intentTargetClass = info.activityInfo.name;
result.add(data);
diff --git a/src/com/android/settings/dashboard/DashboardSummary.java b/src/com/android/settings/dashboard/DashboardSummary.java
index 0e034ff..b48e07e 100644
--- a/src/com/android/settings/dashboard/DashboardSummary.java
+++ b/src/com/android/settings/dashboard/DashboardSummary.java
@@ -17,13 +17,19 @@
package com.android.settings.dashboard;
import android.app.Fragment;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.database.Cursor;
+import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -36,10 +42,14 @@
import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
-import com.android.settings.indexer.Index;
+import com.android.settings.search.Index;
+
+import java.util.HashMap;
public class DashboardSummary extends Fragment {
+ private static final String LOG_TAG = "DashboardSummary";
+
private EditText mEditText;
private ListView mListView;
@@ -124,13 +134,33 @@
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
closeSoftKeyboard();
+
final Cursor cursor = mAdapter.mCursor;
cursor.moveToPosition(position);
- final String fragmentName = cursor.getString(Index.COLUMN_INDEX_FRAGMENT_NAME);
- final String fragmentTitle = cursor.getString(Index.COLUMN_INDEX_FRAGMENT_TITLE);
- ((SettingsActivity) getActivity()).startPreferencePanel(fragmentName, null, 0,
- fragmentTitle, null, 0);
+ final String className = cursor.getString(Index.COLUMN_INDEX_CLASS_NAME);
+ final String screenTitle = cursor.getString(Index.COLUMN_INDEX_SCREEN_TITLE);
+
+ final String action = cursor.getString(Index.COLUMN_INDEX_INTENT_ACTION);
+
+ if (TextUtils.isEmpty(action)) {
+ ((SettingsActivity) getActivity()).startPreferencePanel(className, null, 0,
+ screenTitle, null, 0);
+ } else {
+ final Intent intent = new Intent(action);
+
+ final String targetPackage = cursor.getString(
+ Index.COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE);
+ final String targetClass = cursor.getString(
+ Index.COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS);
+ if (!TextUtils.isEmpty(targetPackage) && !TextUtils.isEmpty(targetClass)) {
+ final ComponentName component =
+ new ComponentName(targetPackage, targetClass);
+ intent.setComponent(component);
+ }
+
+ getActivity().startActivity(intent);
+ }
}
});
@@ -190,8 +220,10 @@
public String title;
public String summary;
public int iconResId;
+ public Context context;
- public SearchResult(String title, String summary, int iconResId) {
+ public SearchResult(Context context, String title, String summary, int iconResId) {
+ this.context = context;
this.title = title;
this.summary = summary;
this.iconResId = iconResId;
@@ -203,9 +235,12 @@
private Cursor mCursor;
private LayoutInflater mInflater;
private boolean mDataValid;
+ private Context mContext;
+ private HashMap<String, Context> mContextMap = new HashMap<String, Context>();
public SearchResultsAdapter(Context context) {
- mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mContext = context;
+ mInflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mDataValid = false;
}
@@ -237,9 +272,29 @@
final String title = mCursor.getString(Index.COLUMN_INDEX_TITLE);
final String summary = mCursor.getString(Index.COLUMN_INDEX_SUMMARY);
final String iconResStr = mCursor.getString(Index.COLUMN_INDEX_ICON);
- final int iconResId =
- TextUtils.isEmpty(iconResStr) ? 0 : Integer.parseInt(iconResStr);
- return new SearchResult(title, summary, iconResId);
+ final String className = mCursor.getString(
+ Index.COLUMN_INDEX_CLASS_NAME);
+ final String packageName = mCursor.getString(
+ Index.COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE);
+
+ Context packageContext;
+ if (TextUtils.isEmpty(className) && !TextUtils.isEmpty(packageName)) {
+ packageContext = mContextMap.get(packageName);
+ if (packageContext == null) {
+ try {
+ packageContext = mContext.createPackageContext(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOG_TAG, "Cannot create Context for package: " + packageName);
+ return null;
+ }
+ mContextMap.put(packageName, packageContext);
+ }
+ } else {
+ packageContext = mContext;
+ }
+ final int iconResId = TextUtils.isEmpty(iconResStr) ?
+ R.drawable.empty_icon : Integer.parseInt(iconResStr);
+ return new SearchResult(packageContext, title, summary, iconResId);
}
return null;
}
@@ -278,7 +333,15 @@
textTitle.setText(result.title);
textSummary.setText(result.summary);
if (result.iconResId != R.drawable.empty_icon) {
- imageView.setImageResource(result.iconResId);
+ final Context packageContext = result.context;
+ final Drawable drawable;
+ try {
+ drawable = packageContext.getDrawable(result.iconResId);
+ imageView.setImageDrawable(drawable);
+ } catch (Resources.NotFoundException nfe) {
+ // Not much we can do except logging
+ Log.e(LOG_TAG, "Cannot load Drawable for " + result.title);
+ }
imageView.setBackgroundResource(R.color.background_search_result_icon);
} else {
imageView.setImageDrawable(null);
diff --git a/src/com/android/settings/indexer/Index.java b/src/com/android/settings/indexer/Index.java
deleted file mode 100644
index 19b545f..0000000
--- a/src/com/android/settings/indexer/Index.java
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.indexer;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.database.sqlite.SQLiteDatabase;
-import android.os.AsyncTask;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.util.Xml;
-import com.android.settings.R;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import static com.android.settings.indexer.IndexDatabaseHelper.Tables;
-import static com.android.settings.indexer.IndexDatabaseHelper.IndexColumns;
-
-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_TITLE = 1;
- public static final int COLUMN_INDEX_SUMMARY = 2;
- public static final int COLUMN_INDEX_FRAGMENT_NAME = 4;
- public static final int COLUMN_INDEX_FRAGMENT_TITLE = 5;
- public static final int COLUMN_INDEX_ICON = 7;
-
- // If you change the order of columns here, you SHOULD change the COLUMN_INDEX_XXX values
- private static final String[] SELECT_COLUMNS = new String[] {
- IndexColumns.DATA_RANK,
- IndexColumns.DATA_TITLE,
- IndexColumns.DATA_SUMMARY,
- IndexColumns.DATA_KEYWORDS,
- IndexColumns.FRAGMENT_NAME,
- IndexColumns.FRAGMENT_TITLE,
- IndexColumns.INTENT,
- IndexColumns.ICON
- };
-
- private static final String[] MATCH_COLUMNS = {
- IndexColumns.DATA_TITLE,
- IndexColumns.DATA_TITLE_NORMALIZED,
- IndexColumns.DATA_SUMMARY,
- IndexColumns.DATA_SUMMARY_NORMALIZED,
- IndexColumns.DATA_KEYWORDS
- };
-
- private static final String EMPTY = "";
- private static final String NON_BREAKING_HYPHEN = "\u2011";
- private static final String HYPHEN = "-";
-
- private static Index sInstance;
-
- private final AtomicBoolean mIsAvailable = new AtomicBoolean(false);
-
- private final UpdateData mUpdateData = new UpdateData();
-
- private final Context mContext;
-
- /**
- * A basic singleton
- */
- public static Index getInstance(Context context) {
- if (sInstance == null) {
- sInstance = new Index(context);
- }
- return sInstance;
- }
-
- public Index(Context context) {
- mContext = context;
- }
-
- public boolean isAvailable() {
- return mIsAvailable.get();
- }
-
- public void addIndexableData(IndexableRef[] array) {
- synchronized (mUpdateData) {
- final int count = array.length;
- for (int n = 0; n < count; n++) {
- mUpdateData.dataToAdd.add(array[n]);
- }
- }
- }
-
- public void deleteIndexableData(String[] array) {
- synchronized (mUpdateData) {
- final int count = array.length;
- for (int n = 0; n < count; n++) {
- mUpdateData.dataToDelete.add(array[n]);
- }
- }
- }
-
- public boolean update() {
- synchronized (mUpdateData) {
- final UpdateIndexTask task = new UpdateIndexTask();
- task.execute(mUpdateData);
- try {
- final boolean result = task.get();
- mUpdateData.clear();
- return result;
- } catch (InterruptedException e) {
- Log.e(LOG_TAG, "Cannot update index: " + e.getMessage());
- return false;
- } catch (ExecutionException e) {
- Log.e(LOG_TAG, "Cannot update index: " + e.getMessage());
- return false;
- }
- }
- }
-
- public Cursor search(String query) {
- final String sql = buildSQL(query);
- Log.d(LOG_TAG, "Query: " + sql);
- return getReadableDatabase().rawQuery(sql, null);
- }
-
- private String buildSQL(String query) {
- StringBuilder sb = new StringBuilder();
- sb.append(buildSQLForColumn(query, MATCH_COLUMNS));
- sb.append(" ORDER BY ");
- sb.append(IndexColumns.DATA_RANK);
- return sb.toString();
- }
-
- private String buildSQLForColumn(String query, String[] columnNames) {
- StringBuilder sb = new StringBuilder();
- sb.append("SELECT ");
- for (int n = 0; n < SELECT_COLUMNS.length; n++) {
- sb.append(SELECT_COLUMNS[n]);
- if (n < SELECT_COLUMNS.length - 1) {
- sb.append(", ");
- }
- }
- sb.append(" FROM ");
- sb.append(Tables.TABLE_PREFS_INDEX);
- sb.append(" WHERE ");
- sb.append(buildWhereStringForColumns(query, columnNames));
-
- return sb.toString();
- }
-
- private String buildWhereStringForColumns(String query, String[] columnNames) {
- final StringBuilder sb = new StringBuilder(Tables.TABLE_PREFS_INDEX);
- sb.append(" MATCH ");
- DatabaseUtils.appendEscapedSQLString(sb, buildMatchStringForColumns(query, columnNames));
- sb.append(" AND ");
- sb.append(IndexColumns.LOCALE);
- sb.append(" = ");
- DatabaseUtils.appendEscapedSQLString(sb, Locale.getDefault().toString());
- return sb.toString();
- }
-
- private String buildMatchStringForColumns(String query, String[] columnNames) {
- final String value = query + "*";
- StringBuilder sb = new StringBuilder();
- final int count = columnNames.length;
- for (int n = 0; n < count; n++) {
- sb.append(columnNames[n]);
- sb.append(":");
- sb.append(value);
- if (n < count - 1) {
- sb.append(" OR ");
- }
- }
- return sb.toString();
- }
-
- private SQLiteDatabase getReadableDatabase() {
- return IndexDatabaseHelper.getInstance(mContext).getReadableDatabase();
- }
-
- private SQLiteDatabase getWritableDatabase() {
- return IndexDatabaseHelper.getInstance(mContext).getWritableDatabase();
- }
-
- /**
- * A private class to describe the update data for the Index database
- */
- private class UpdateData {
- public List<IndexableRef> dataToAdd;
- public List<String> dataToDelete;
-
- public UpdateData() {
- dataToAdd = new ArrayList<IndexableRef>();
- dataToDelete = new ArrayList<String>();
- }
-
- public void clear() {
- dataToAdd.clear();
- dataToDelete.clear();
- }
- }
-
- /**
- * A private class for updating the Index database
- */
- private class UpdateIndexTask extends AsyncTask<UpdateData, Integer, Boolean> {
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- mIsAvailable.set(false);
- }
-
- @Override
- protected void onPostExecute(Boolean aBoolean) {
- super.onPostExecute(aBoolean);
- mIsAvailable.set(true);
- }
-
- @Override
- protected Boolean doInBackground(UpdateData... params) {
- boolean result = false;
-
- final List<IndexableRef> dataToAdd = params[0].dataToAdd;
- final List<String> dataToDelete = params[0].dataToDelete;
- final SQLiteDatabase database = getWritableDatabase();
- final String localeStr = Locale.getDefault().toString();
-
- try {
- database.beginTransaction();
- if (dataToAdd.size() > 0) {
- processDataToAdd(database, localeStr, dataToAdd);
- }
- if (dataToDelete.size() > 0) {
- processDataToDelete(database, localeStr, dataToDelete);
- }
- database.setTransactionSuccessful();
- result = true;
- } finally {
- database.endTransaction();
- }
- return result;
- }
-
- private boolean processDataToDelete(SQLiteDatabase database, String localeStr,
- List<String> 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 long now = System.currentTimeMillis();
- Log.d(LOG_TAG, "Deleting data for locale '" + localeStr + "' took " +
- (now - current) + " millis");
- return result;
- }
-
- private boolean processDataToAdd(SQLiteDatabase database, String localeStr,
- List<IndexableRef> dataToAdd) {
- if (isLocaleAlreadyIndexed(database, localeStr)) {
- Log.d(LOG_TAG, "Locale '" + localeStr + "' is already indexed");
- return true;
- }
-
- boolean result = false;
- final long current = System.currentTimeMillis();
-
- final int count = dataToAdd.size();
- for (int n = 0; n < count; n++) {
- final IndexableRef ref = dataToAdd.get(n);
- indexOneRef(database, localeStr, ref);
- }
-
- final long now = System.currentTimeMillis();
- Log.d(LOG_TAG, "Indexing locale '" + localeStr + "' took " +
- (now - current) + " millis");
- return result;
- }
-
- private void indexOneRef(SQLiteDatabase database, String localeStr, IndexableRef ref) {
- if (ref.xmlResId > 0) {
- indexFromResource(database, localeStr, ref.xmlResId, ref.fragmentName,
- ref.iconResId, ref.rank);
- } else if (!TextUtils.isEmpty(ref.fragmentName)) {
- indexRawData(database, localeStr, ref);
- }
- }
-
- private void indexRawData(SQLiteDatabase database, String localeStr, IndexableRef ref) {
- try {
- final Class<?> clazz = Class.forName(ref.fragmentName);
- if (Indexable.class.isAssignableFrom(clazz)) {
- final Field f = clazz.getField("INDEX_DATA_PROVIDER");
- final Indexable.IndexDataProvider provider =
- (Indexable.IndexDataProvider) f.get(null);
-
- final List<IndexableData> data = provider.getRawDataToIndex(mContext);
-
- final int size = data.size();
- for (int i = 0; i < size; i++) {
- IndexableData raw = data.get(i);
-
- // Should be the same locale as the one we are processing
- if (!raw.locale.toString().equalsIgnoreCase(localeStr)) {
- continue;
- }
-
- inserOneRowWithFilteredData(database, localeStr,
- raw.title,
- raw.summary,
- ref.fragmentName,
- raw.fragmentTitle,
- ref.iconResId,
- ref.rank,
- raw.keywords);
- }
- }
- } catch (ClassNotFoundException e) {
- Log.e(LOG_TAG, "Cannot find class: " + ref.fragmentName, e);
- } catch (NoSuchFieldException e) {
- Log.e(LOG_TAG, "Cannot find field 'INDEX_DATA_PROVIDER'", e);
- } catch (IllegalAccessException e) {
- Log.e(LOG_TAG, "Illegal access to field 'INDEX_DATA_PROVIDER'", e);
- }
- }
-
- private boolean isLocaleAlreadyIndexed(SQLiteDatabase database, String locale) {
- Cursor cursor = null;
- boolean result = false;
- final StringBuilder sb = new StringBuilder(IndexColumns.LOCALE);
- sb.append(" = ");
- DatabaseUtils.appendEscapedSQLString(sb, locale);
- try {
- // We care only for 1 row
- cursor = database.query(Tables.TABLE_PREFS_INDEX, null,
- sb.toString(), null, null, null, null, "1");
- final int count = cursor.getCount();
- result = (count >= 1);
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- return result;
- }
-
- private void indexFromResource(SQLiteDatabase database, String localeStr, int xmlResId,
- String fragmentName, int iconResId, int rank) {
- XmlResourceParser parser = null;
- try {
- parser = mContext.getResources().getXml(xmlResId);
-
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && type != XmlPullParser.START_TAG) {
- // Parse next until start tag is found
- }
-
- String nodeName = parser.getName();
- if (!"PreferenceScreen".equals(nodeName)) {
- throw new RuntimeException(
- "XML document must start with <PreferenceScreen> tag; found"
- + nodeName + " at " + parser.getPositionDescription());
- }
-
- final int outerDepth = parser.getDepth();
- final AttributeSet attrs = Xml.asAttributeSet(parser);
- final String fragmentTitle = getDataTitle(attrs);
-
- String title = getDataTitle(attrs);
- String summary = getDataSummary(attrs);
- String keywords = getDataKeywords(attrs);
-
- // Insert rows for the main PreferenceScreen node. Rewrite the data for removing
- // hyphens.
- inserOneRowWithFilteredData(database, localeStr, title, summary, fragmentName,
- fragmentTitle, iconResId, rank, keywords);
-
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- title = getDataTitle(attrs);
- summary = getDataSummary(attrs);
- keywords = getDataKeywords(attrs);
-
- // Insert rows for the child nodes of PreferenceScreen
- inserOneRowWithFilteredData(database, localeStr, title, summary, fragmentName,
- fragmentTitle, iconResId, rank, keywords);
- }
-
- } catch (XmlPullParserException e) {
- throw new RuntimeException("Error parsing PreferenceScreen", e);
- } catch (IOException e) {
- throw new RuntimeException("Error parsing PreferenceScreen", e);
- } finally {
- if (parser != null) parser.close();
- }
- }
-
- private void inserOneRowWithFilteredData(SQLiteDatabase database, String locale,
- String title, String summary, String fragmentName, String fragmentTitle,
- int iconResId, int rank, String keywords) {
-
- String updatedTitle;
- if (title != null) {
- updatedTitle = title.replaceAll(NON_BREAKING_HYPHEN, HYPHEN);
- }
- else {
- updatedTitle = EMPTY;
- }
-
- String updatedSummary;
- if (summary != null) {
- updatedSummary = summary.replaceAll(NON_BREAKING_HYPHEN, HYPHEN);
- } else {
- updatedSummary = EMPTY;
- }
-
- String normalizedTitle = updatedTitle.replaceAll(HYPHEN, EMPTY);
- String normalizedSummary = updatedSummary.replaceAll(HYPHEN, EMPTY);
-
- insertOneRow(database, locale,
- updatedTitle, normalizedTitle, updatedSummary, normalizedSummary,
- fragmentName, fragmentTitle, iconResId, rank, keywords);
- }
-
- private void insertOneRow(SQLiteDatabase database, String locale,
- String updatedTitle, String normalizedTitle,
- String updatedSummary, String normalizedSummary,
- String fragmentName, String fragmentTitle,
- int iconResId, int rank, String keywords) {
-
- if (TextUtils.isEmpty(updatedTitle)) {
- return;
- }
- ContentValues values = new ContentValues();
- values.put(IndexColumns.LOCALE, locale);
- values.put(IndexColumns.DATA_RANK, rank);
- values.put(IndexColumns.DATA_TITLE, updatedTitle);
- values.put(IndexColumns.DATA_TITLE_NORMALIZED, normalizedTitle);
- values.put(IndexColumns.DATA_SUMMARY, updatedSummary);
- values.put(IndexColumns.DATA_SUMMARY_NORMALIZED, normalizedSummary);
- values.put(IndexColumns.DATA_KEYWORDS, keywords);
- values.put(IndexColumns.FRAGMENT_NAME, fragmentName);
- values.put(IndexColumns.FRAGMENT_TITLE, fragmentTitle);
- values.put(IndexColumns.INTENT, "");
- values.put(IndexColumns.ICON, iconResId);
-
- database.insertOrThrow(Tables.TABLE_PREFS_INDEX, null, values);
- }
-
- private int delete(SQLiteDatabase database, String title) {
- final String whereClause = IndexColumns.DATA_TITLE + "=?";
- final String[] whereArgs = new String[] { title };
-
- return database.delete(Tables.TABLE_PREFS_INDEX, whereClause, whereArgs);
- }
-
- private String getDataTitle(AttributeSet attrs) {
- return getData(attrs,
- com.android.internal.R.styleable.Preference,
- com.android.internal.R.styleable.Preference_title);
- }
-
- private String getDataSummary(AttributeSet attrs) {
- return getData(attrs,
- com.android.internal.R.styleable.Preference,
- com.android.internal.R.styleable.Preference_summary);
- }
-
- private String getDataKeywords(AttributeSet attrs) {
- return getData(attrs,
- R.styleable.Preference,
- R.styleable.Preference_keywords);
- }
-
- private String getData(AttributeSet set, int[] attrs, int resId) {
- final TypedArray sa = mContext.obtainStyledAttributes(set, attrs);
- final TypedValue tv = sa.peekValue(resId);
-
- CharSequence data = null;
- if (tv != null && tv.type == TypedValue.TYPE_STRING) {
- if (tv.resourceId != 0) {
- data = mContext.getText(tv.resourceId);
- } else {
- data = tv.string;
- }
- }
- return (data != null) ? data.toString() : null;
- }
- }
-}
diff --git a/src/com/android/settings/indexer/Indexable.java b/src/com/android/settings/indexer/Indexable.java
deleted file mode 100644
index 1b29b75..0000000
--- a/src/com/android/settings/indexer/Indexable.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.indexer;
-
-import android.content.Context;
-
-import java.util.List;
-
-/**
- * Interface for classes whose instances can provide data for indexing.
- *
- * Classes implementing the Indexable interface must have a static field called
- * <code>INDEX_DATA_PROVIDER</code>, which is an object implementing the
- * {@link Indexable.IndexDataProvider Indexable.IndexDataProvider} interface.
- *
- * See {@link IndexableRef} and {@link IndexableData}.
- *
- */
-public interface Indexable {
-
- public interface IndexDataProvider {
- /**
- * Return a list of references for indexing. See {@link IndexableRef}
- *
- * @param context the context
- * @return a list of {@link IndexableRef} references. Can be null.
- */
- List<IndexableRef> getRefsToIndex(Context context);
-
- /**
- * Return a list of raw data for indexing. See {@link IndexableData}
- *
- * @param context the context
- * @return a list of {@link IndexableData} references. Can be null.
- */
- List<IndexableData> getRawDataToIndex(Context context);
- }
-}
diff --git a/src/com/android/settings/indexer/IndexableRef.java b/src/com/android/settings/indexer/IndexableRef.java
deleted file mode 100644
index c1ebcca..0000000
--- a/src/com/android/settings/indexer/IndexableRef.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.indexer;
-
-/**
- * Indexable Reference.
- *
- * This class wraps a set of information representing data that can be indexed for a high
- * level (see {@link android.preference.PreferenceScreen}).
- *
- * rank: is the rank of the data (basically its order in the list of Settings)
- * xmlResId: is the resource Id of a PreferenceScreen xml file
- * fragmentName: is the fragment class name associated with the data
- * iconRedId: is the resource Id of an icon that represents the data
- *
- * See {@link Indexable} and {@link IndexableData}.
- *
- */
-public class IndexableRef {
-
- public int rank;
- public int xmlResId;
- public String fragmentName;
- public int iconResId;
-
- public IndexableRef(int rank, int dataResId, String name, int iconResId) {
- this.rank = rank;
- this.xmlResId = dataResId;
- this.fragmentName = name;
- this.iconResId = iconResId;
- }
-}
\ No newline at end of file
diff --git a/src/com/android/settings/search/Index.java b/src/com/android/settings/search/Index.java
new file mode 100644
index 0000000..3128547
--- /dev/null
+++ b/src/com/android/settings/search/Index.java
@@ -0,0 +1,741 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.search;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.provider.SearchIndexableData;
+import android.provider.SearchIndexableResource;
+import android.provider.SearchIndexablesContract;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.util.Xml;
+import com.android.settings.R;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static com.android.settings.search.IndexDatabaseHelper.Tables;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns;
+
+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_TITLE = 1;
+ public static final int COLUMN_INDEX_SUMMARY = 2;
+ public static final int COLUMN_INDEX_CLASS_NAME = 4;
+ public static final int COLUMN_INDEX_SCREEN_TITLE = 5;
+ public static final int COLUMN_INDEX_ICON = 6;
+ public static final int COLUMN_INDEX_INTENT_ACTION = 7;
+ public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 8;
+ public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 9;
+
+ // If you change the order of columns here, you SHOULD change the COLUMN_INDEX_XXX values
+ private static final String[] SELECT_COLUMNS = new String[] {
+ IndexColumns.DATA_RANK,
+ IndexColumns.DATA_TITLE,
+ IndexColumns.DATA_SUMMARY,
+ IndexColumns.DATA_KEYWORDS,
+ IndexColumns.CLASS_NAME,
+ IndexColumns.SCREEN_TITLE,
+ IndexColumns.ICON,
+ IndexColumns.INTENT_ACTION,
+ IndexColumns.INTENT_TARGET_PACKAGE,
+ IndexColumns.INTENT_TARGET_CLASS
+ };
+
+ private static final String[] MATCH_COLUMNS = {
+ IndexColumns.DATA_TITLE,
+ IndexColumns.DATA_TITLE_NORMALIZED,
+ IndexColumns.DATA_SUMMARY,
+ IndexColumns.DATA_SUMMARY_NORMALIZED,
+ IndexColumns.DATA_KEYWORDS
+ };
+
+ private static final String EMPTY = "";
+ private static final String NON_BREAKING_HYPHEN = "\u2011";
+ private static final String HYPHEN = "-";
+
+ private static Index sInstance;
+
+ private final AtomicBoolean mIsAvailable = new AtomicBoolean(false);
+
+ private final UpdateData mUpdateData = new UpdateData();
+
+ private final Context mContext;
+
+ /**
+ * A basic singleton
+ */
+ public static Index getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new Index(context);
+ }
+ return sInstance;
+ }
+
+ public Index(Context context) {
+ mContext = context;
+ }
+
+ public boolean isAvailable() {
+ return mIsAvailable.get();
+ }
+
+ public void addIndexableData(SearchIndexableData data) {
+ synchronized (mUpdateData) {
+ mUpdateData.dataToAdd.add(data);
+ }
+ }
+
+ public void addIndexableData(SearchIndexableResource[] array) {
+ synchronized (mUpdateData) {
+ final int count = array.length;
+ for (int n = 0; n < count; n++) {
+ mUpdateData.dataToAdd.add(array[n]);
+ }
+ }
+ }
+
+ public void deleteIndexableData(String[] array) {
+ synchronized (mUpdateData) {
+ final int count = array.length;
+ for (int n = 0; n < count; n++) {
+ mUpdateData.dataToDelete.add(array[n]);
+ }
+ }
+ }
+
+ 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);
+ final String authority = info.providerInfo.authority;
+ final String packageName = info.providerInfo.packageName;
+ 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);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(LOG_TAG, "Could not create context for " + packageName + ": "
+ + Log.getStackTraceString(e));
+ continue;
+ }
+ }
+
+ return updateInternal();
+ }
+
+ private static Uri buildUriForXmlResources(String authority) {
+ return Uri.parse("content://" + authority + "/" +
+ SearchIndexablesContract.INDEXABLES_XML_RES_PATH);
+ }
+
+ private static Uri buildUriForRawData(String authority) {
+ return Uri.parse("content://" + authority + "/" +
+ SearchIndexablesContract.INDEXABLES_RAW_PATH);
+ }
+
+ private void addIndexablesForXmlResourceUri(Context context, String packageName, Uri uri,
+ String[] projection) {
+ final ContentResolver resolver = context.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;
+ }
+
+ try {
+ final int count = cursor.getCount();
+ if (count > 0) {
+ while (cursor.moveToNext()) {
+ final int rank = cursor.getInt(0);
+ final int xmlResId = cursor.getInt(1);
+
+ final String className = cursor.getString(2);
+ final int iconResId = cursor.getInt(3);
+
+ final String action = cursor.getString(4);
+ final String targetPackage = cursor.getString(5);
+ final String targetClass = cursor.getString(6);
+
+ SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.rank = rank;
+ sir.xmlResId = xmlResId;
+ sir.className = className;
+ sir.packageName = packageName;
+ sir.iconResId = iconResId;
+ sir.intentAction = action;
+ sir.intentTargetPackage = targetPackage;
+ sir.intentTargetClass = targetClass;
+
+ addIndexableData(sir);
+ }
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
+ private void addIndexablesForRawDataUri(Context context, String packageName, Uri uri,
+ String[] projection) {
+ final ContentResolver resolver = context.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;
+ }
+
+ try {
+ 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 summary = cursor.getString(2);
+ final String keywords = cursor.getString(3);
+
+ final String screenTitle = cursor.getString(4);
+
+ final String className = cursor.getString(5);
+ final int iconResId = cursor.getInt(6);
+
+ final String action = cursor.getString(7);
+ final String targetPackage = cursor.getString(8);
+ final String targetClass = cursor.getString(9);
+
+ SearchIndexableRaw data = new SearchIndexableRaw(context);
+ data.rank = rank;
+ data.title = title;
+ data.summary = summary;
+ data.keywords = keywords;
+ data.screenTitle = screenTitle;
+ data.className = className;
+ data.packageName = packageName;
+ data.iconResId = iconResId;
+ data.intentAction = action;
+ data.intentTargetPackage = targetPackage;
+ data.intentTargetClass = targetClass;
+
+ addIndexableData(data);
+ }
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
+ private boolean updateInternal() {
+ synchronized (mUpdateData) {
+ final UpdateIndexTask task = new UpdateIndexTask();
+ task.execute(mUpdateData);
+ try {
+ final boolean result = task.get();
+ mUpdateData.clear();
+ return result;
+ } catch (InterruptedException e) {
+ Log.e(LOG_TAG, "Cannot update index: " + e.getMessage());
+ return false;
+ } catch (ExecutionException e) {
+ Log.e(LOG_TAG, "Cannot update index: " + e.getMessage());
+ return false;
+ }
+ }
+ }
+
+ public Cursor search(String query) {
+ final String sql = buildSQL(query);
+ Log.d(LOG_TAG, "Query: " + sql);
+ return getReadableDatabase().rawQuery(sql, null);
+ }
+
+ private String buildSQL(String query) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(buildSQLForColumn(query, MATCH_COLUMNS));
+ sb.append(" ORDER BY ");
+ sb.append(IndexColumns.DATA_RANK);
+ return sb.toString();
+ }
+
+ private String buildSQLForColumn(String query, String[] columnNames) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("SELECT ");
+ for (int n = 0; n < SELECT_COLUMNS.length; n++) {
+ sb.append(SELECT_COLUMNS[n]);
+ if (n < SELECT_COLUMNS.length - 1) {
+ sb.append(", ");
+ }
+ }
+ sb.append(" FROM ");
+ sb.append(Tables.TABLE_PREFS_INDEX);
+ sb.append(" WHERE ");
+ sb.append(buildWhereStringForColumns(query, columnNames));
+
+ return sb.toString();
+ }
+
+ private String buildWhereStringForColumns(String query, String[] columnNames) {
+ final StringBuilder sb = new StringBuilder(Tables.TABLE_PREFS_INDEX);
+ sb.append(" MATCH ");
+ DatabaseUtils.appendEscapedSQLString(sb, buildMatchStringForColumns(query, columnNames));
+ sb.append(" AND ");
+ sb.append(IndexColumns.LOCALE);
+ sb.append(" = ");
+ DatabaseUtils.appendEscapedSQLString(sb, Locale.getDefault().toString());
+ return sb.toString();
+ }
+
+ private String buildMatchStringForColumns(String query, String[] columnNames) {
+ final String value = query + "*";
+ StringBuilder sb = new StringBuilder();
+ final int count = columnNames.length;
+ for (int n = 0; n < count; n++) {
+ sb.append(columnNames[n]);
+ sb.append(":");
+ sb.append(value);
+ if (n < count - 1) {
+ sb.append(" OR ");
+ }
+ }
+ return sb.toString();
+ }
+
+ private SQLiteDatabase getReadableDatabase() {
+ return IndexDatabaseHelper.getInstance(mContext).getReadableDatabase();
+ }
+
+ private SQLiteDatabase getWritableDatabase() {
+ return IndexDatabaseHelper.getInstance(mContext).getWritableDatabase();
+ }
+
+ /**
+ * A private class to describe the update data for the Index database
+ */
+ private class UpdateData {
+ public List<SearchIndexableData> dataToAdd;
+ public List<String> dataToDelete;
+
+ public UpdateData() {
+ dataToAdd = new ArrayList<SearchIndexableData>();
+ dataToDelete = new ArrayList<String>();
+ }
+
+ public void clear() {
+ dataToAdd.clear();
+ dataToDelete.clear();
+ }
+ }
+
+ /**
+ * A private class for updating the Index database
+ */
+ private class UpdateIndexTask extends AsyncTask<UpdateData, Integer, Boolean> {
+
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ mIsAvailable.set(false);
+ }
+
+ @Override
+ protected void onPostExecute(Boolean aBoolean) {
+ super.onPostExecute(aBoolean);
+ mIsAvailable.set(true);
+ }
+
+ @Override
+ protected Boolean doInBackground(UpdateData... params) {
+ boolean result = false;
+
+ final List<SearchIndexableData> dataToAdd = params[0].dataToAdd;
+ final List<String> dataToDelete = params[0].dataToDelete;
+ final SQLiteDatabase database = getWritableDatabase();
+ final String localeStr = Locale.getDefault().toString();
+
+ try {
+ database.beginTransaction();
+ if (dataToAdd.size() > 0) {
+ processDataToAdd(database, localeStr, dataToAdd);
+ }
+ if (dataToDelete.size() > 0) {
+ processDataToDelete(database, localeStr, dataToDelete);
+ }
+ database.setTransactionSuccessful();
+ result = true;
+ } finally {
+ database.endTransaction();
+ }
+ return result;
+ }
+
+ private boolean processDataToDelete(SQLiteDatabase database, String localeStr,
+ List<String> 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 long now = System.currentTimeMillis();
+ Log.d(LOG_TAG, "Deleting data for locale '" + localeStr + "' took " +
+ (now - current) + " millis");
+ return result;
+ }
+
+ private boolean processDataToAdd(SQLiteDatabase database, String localeStr,
+ List<SearchIndexableData> dataToAdd) {
+ if (isLocaleAlreadyIndexed(database, localeStr)) {
+ Log.d(LOG_TAG, "Locale '" + localeStr + "' is already indexed");
+ return true;
+ }
+
+ boolean result = false;
+ final long current = System.currentTimeMillis();
+
+ final int count = dataToAdd.size();
+ for (int n = 0; n < count; n++) {
+ final SearchIndexableData data = dataToAdd.get(n);
+ if (data instanceof SearchIndexableResource) {
+ indexOneResource(database, localeStr, (SearchIndexableResource) data);
+ } else if (data instanceof SearchIndexableRaw) {
+ indexOneRaw(database, localeStr, (SearchIndexableRaw) data);
+ }
+ }
+
+ final long now = System.currentTimeMillis();
+ Log.d(LOG_TAG, "Indexing locale '" + localeStr + "' took " +
+ (now - current) + " millis");
+ return result;
+ }
+
+ private void indexOneResource(SQLiteDatabase database, String localeStr,
+ SearchIndexableResource sir) {
+ if (sir.xmlResId > 0) {
+ indexFromResource(sir.context, database, localeStr,
+ sir.xmlResId, sir.className, sir.iconResId, sir.rank,
+ sir.intentAction, sir.intentTargetPackage, sir.intentTargetClass);
+ } else if (!TextUtils.isEmpty(sir.className)) {
+ indexFromLocalProvider(database, localeStr, sir);
+ }
+ }
+
+ 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("SEARCH_INDEX_DATA_PROVIDER");
+ final Indexable.SearchIndexProvider provider =
+ (Indexable.SearchIndexProvider) f.get(null);
+
+ final List<SearchIndexableRaw> rawList =
+ provider.getRawDataToIndex(sir.context);
+ 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;
+ }
+
+ insertOneRowWithFilteredData(database, localeStr,
+ raw.title,
+ raw.summary,
+ sir.className,
+ raw.screenTitle,
+ sir.iconResId,
+ sir.rank,
+ raw.keywords,
+ raw.intentAction,
+ raw.intentTargetPackage,
+ raw.intentTargetClass
+ );
+ }
+ }
+
+ final List<SearchIndexableResource> resList =
+ provider.getXmlResourcesToIndex(sir.context);
+ 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;
+ }
+
+ indexFromResource(sir.context, database, localeStr,
+ item.xmlResId, item.className, item.iconResId, item.rank,
+ item.intentAction, item.intentTargetPackage,
+ item.intentTargetClass);
+ }
+ }
+ }
+ } catch (ClassNotFoundException e) {
+ Log.e(LOG_TAG, "Cannot find class: " + sir.className, e);
+ } catch (NoSuchFieldException e) {
+ Log.e(LOG_TAG, "Cannot find field 'SEARCH_INDEX_DATA_PROVIDER'", e);
+ } catch (IllegalAccessException e) {
+ Log.e(LOG_TAG, "Illegal access to field 'SEARCH_INDEX_DATA_PROVIDER'", e);
+ }
+ }
+
+ 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;
+ }
+
+ insertOneRowWithFilteredData(database, localeStr,
+ raw.title,
+ raw.summary,
+ raw.className,
+ raw.screenTitle,
+ raw.iconResId,
+ raw.rank,
+ raw.keywords,
+ raw.intentAction,
+ raw.intentTargetPackage,
+ raw.intentTargetClass
+ );
+ }
+
+ private boolean isLocaleAlreadyIndexed(SQLiteDatabase database, String locale) {
+ Cursor cursor = null;
+ boolean result = false;
+ final StringBuilder sb = new StringBuilder(IndexColumns.LOCALE);
+ sb.append(" = ");
+ DatabaseUtils.appendEscapedSQLString(sb, locale);
+ try {
+ // We care only for 1 row
+ cursor = database.query(Tables.TABLE_PREFS_INDEX, null,
+ sb.toString(), null, null, null, null, "1");
+ final int count = cursor.getCount();
+ result = (count >= 1);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ return result;
+ }
+
+ private void indexFromResource(Context context, SQLiteDatabase database, String localeStr,
+ int xmlResId, String fragmentName, int iconResId, int rank,
+ String intentAction, String intentTargetPackage, String intentTargetClass) {
+
+ XmlResourceParser parser = null;
+ try {
+ parser = context.getResources().getXml(xmlResId);
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ // Parse next until start tag is found
+ }
+
+ String nodeName = parser.getName();
+ if (!"PreferenceScreen".equals(nodeName)) {
+ throw new RuntimeException(
+ "XML document must start with <PreferenceScreen> tag; found"
+ + nodeName + " at " + parser.getPositionDescription());
+ }
+
+ 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);
+
+ // Insert rows for the main PreferenceScreen node. Rewrite the data for removing
+ // hyphens.
+ insertOneRowWithFilteredData(database, localeStr, title, summary, fragmentName,
+ screenTitle, iconResId, rank, keywords,
+ intentAction, intentTargetPackage, intentTargetClass);
+
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ title = getDataTitle(context, attrs);
+ summary = getDataSummary(context, attrs);
+ keywords = getDataKeywords(context, attrs);
+
+ // Insert rows for the child nodes of PreferenceScreen
+ insertOneRowWithFilteredData(database, localeStr, title, summary, fragmentName,
+ screenTitle, iconResId, rank, keywords,
+ intentAction, intentTargetPackage, intentTargetClass);
+ }
+
+ } catch (XmlPullParserException e) {
+ throw new RuntimeException("Error parsing PreferenceScreen", e);
+ } catch (IOException e) {
+ throw new RuntimeException("Error parsing PreferenceScreen", e);
+ } finally {
+ if (parser != null) parser.close();
+ }
+ }
+
+ private void insertOneRowWithFilteredData(SQLiteDatabase database, String locale,
+ String title, String summary, String className, String screenTitle,
+ int iconResId, int rank, String keywords,
+ String intentAction, String intentTargetPackage, String intentTargetClass) {
+
+ String updatedTitle;
+ if (title != null) {
+ updatedTitle = title.replaceAll(NON_BREAKING_HYPHEN, HYPHEN);
+ }
+ else {
+ updatedTitle = EMPTY;
+ }
+
+ String updatedSummary;
+ if (summary != null) {
+ updatedSummary = summary.replaceAll(NON_BREAKING_HYPHEN, HYPHEN);
+ } else {
+ updatedSummary = EMPTY;
+ }
+
+ String normalizedTitle = updatedTitle.replaceAll(HYPHEN, EMPTY);
+ String normalizedSummary = updatedSummary.replaceAll(HYPHEN, EMPTY);
+
+ insertOneRow(database, locale,
+ updatedTitle, normalizedTitle, updatedSummary, normalizedSummary,
+ className, screenTitle, iconResId, rank, keywords,
+ intentAction, intentTargetPackage, intentTargetClass);
+ }
+
+ private void insertOneRow(SQLiteDatabase database, String locale,
+ String updatedTitle, String normalizedTitle,
+ String updatedSummary, String normalizedSummary,
+ String className, String screenTitle,
+ int iconResId, int rank, String keywords,
+ String intentAction, String intentTargetPackage, String intentTargetClass) {
+
+ if (TextUtils.isEmpty(updatedTitle)) {
+ return;
+ }
+ ContentValues values = new ContentValues();
+ values.put(IndexColumns.LOCALE, locale);
+ values.put(IndexColumns.DATA_RANK, rank);
+ values.put(IndexColumns.DATA_TITLE, updatedTitle);
+ values.put(IndexColumns.DATA_TITLE_NORMALIZED, normalizedTitle);
+ values.put(IndexColumns.DATA_SUMMARY, updatedSummary);
+ values.put(IndexColumns.DATA_SUMMARY_NORMALIZED, normalizedSummary);
+ values.put(IndexColumns.DATA_KEYWORDS, keywords);
+ values.put(IndexColumns.CLASS_NAME, className);
+ values.put(IndexColumns.SCREEN_TITLE, screenTitle);
+ values.put(IndexColumns.INTENT_ACTION, intentAction);
+ values.put(IndexColumns.INTENT_TARGET_PACKAGE, intentTargetPackage);
+ values.put(IndexColumns.INTENT_TARGET_CLASS, intentTargetClass);
+ values.put(IndexColumns.ICON, iconResId);
+
+ database.insertOrThrow(Tables.TABLE_PREFS_INDEX, null, values);
+ }
+
+ private int delete(SQLiteDatabase database, String title) {
+ final String whereClause = IndexColumns.DATA_TITLE + "=?";
+ final String[] whereArgs = new String[] { title };
+
+ return database.delete(Tables.TABLE_PREFS_INDEX, whereClause, whereArgs);
+ }
+
+ private String getDataTitle(Context context, AttributeSet attrs) {
+ return getData(context, attrs,
+ com.android.internal.R.styleable.Preference,
+ com.android.internal.R.styleable.Preference_title);
+ }
+
+ private String getDataSummary(Context context, AttributeSet attrs) {
+ return getData(context, attrs,
+ com.android.internal.R.styleable.Preference,
+ com.android.internal.R.styleable.Preference_summary);
+ }
+
+ private String getDataKeywords(Context context, AttributeSet attrs) {
+ return getData(context, attrs,
+ R.styleable.Preference,
+ R.styleable.Preference_keywords);
+ }
+
+ private String getData(Context context, AttributeSet set, int[] attrs, int resId) {
+ final TypedArray sa = context.obtainStyledAttributes(set, attrs);
+ final TypedValue tv = sa.peekValue(resId);
+
+ CharSequence data = null;
+ if (tv != null && tv.type == TypedValue.TYPE_STRING) {
+ if (tv.resourceId != 0) {
+ data = context.getText(tv.resourceId);
+ } else {
+ data = tv.string;
+ }
+ }
+ return (data != null) ? data.toString() : null;
+ }
+ }
+}
diff --git a/src/com/android/settings/indexer/IndexDatabaseHelper.java b/src/com/android/settings/search/IndexDatabaseHelper.java
similarity index 85%
rename from src/com/android/settings/indexer/IndexDatabaseHelper.java
rename to src/com/android/settings/search/IndexDatabaseHelper.java
index 3e6396e..1132d3f 100644
--- a/src/com/android/settings/indexer/IndexDatabaseHelper.java
+++ b/src/com/android/settings/search/IndexDatabaseHelper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.indexer;
+package com.android.settings.search;
import android.content.Context;
import android.database.Cursor;
@@ -28,7 +28,7 @@
private static final String TAG = "IndexDatabaseHelper";
private static final String DATABASE_NAME = "search_index.db";
- private static final int DATABASE_VERSION = 101;
+ private static final int DATABASE_VERSION = 102;
public interface Tables {
public static final String TABLE_PREFS_INDEX = "prefs_index";
@@ -43,9 +43,11 @@
public static final String DATA_SUMMARY = "data_summary";
public static final String DATA_SUMMARY_NORMALIZED = "data_summary_normalized";
public static final String DATA_KEYWORDS = "data_keywords";
- public static final String FRAGMENT_NAME = "fragment_name";
- public static final String FRAGMENT_TITLE = "fragment_title";
- public static final String INTENT = "intent";
+ public static final String CLASS_NAME = "class_name";
+ public static final String SCREEN_TITLE = "screen_title";
+ public static final String INTENT_ACTION = "intent_action";
+ public static final String INTENT_TARGET_PACKAGE = "intent_target_package";
+ public static final String INTENT_TARGET_CLASS = "intent_target_class";
public static final String ICON = "icon";
}
@@ -70,13 +72,17 @@
", " +
IndexColumns.DATA_KEYWORDS +
", " +
- IndexColumns.FRAGMENT_NAME +
+ IndexColumns.SCREEN_TITLE +
", " +
- IndexColumns.FRAGMENT_TITLE +
- ", " +
- IndexColumns.INTENT +
+ IndexColumns.CLASS_NAME +
", " +
IndexColumns.ICON +
+ ", " +
+ IndexColumns.INTENT_ACTION +
+ ", " +
+ IndexColumns.INTENT_TARGET_PACKAGE +
+ ", " +
+ IndexColumns.INTENT_TARGET_CLASS +
");";
private static final String CREATE_META_TABLE =
@@ -119,9 +125,9 @@
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- if (newVersion > 100) {
- Log.w(TAG, "Detected schema version 100. " +
- "Index needs to be rebuilt for schema version 101");
+ if (oldVersion == 100 || oldVersion == 101) {
+ Log.w(TAG, "Detected schema version 100 or 101. " +
+ "Index needs to be rebuilt for schema version 102");
// We need to drop the tables and recreate them
dropTables(db);
bootstrapDB(db);
diff --git a/src/com/android/settings/search/Indexable.java b/src/com/android/settings/search/Indexable.java
new file mode 100644
index 0000000..54070fb
--- /dev/null
+++ b/src/com/android/settings/search/Indexable.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.search;
+
+import android.content.Context;
+import android.provider.SearchIndexableResource;
+
+import java.util.List;
+
+/**
+ * Interface for classes whose instances can provide data for indexing.
+ *
+ * Classes implementing the Indexable interface must have a static field called
+ * <code>SEARCH_INDEX_DATA_PROVIDER</code>, which is an object implementing the
+ * {@link Indexable.SearchIndexProvider} interface.
+ *
+ * See {@link android.provider.SearchIndexableResource} and {@link SearchIndexableRaw}.
+ *
+ */
+public interface Indexable {
+
+ public interface SearchIndexProvider {
+ /**
+ * Return a list of references for indexing.
+ *
+ * See {@link android.provider.SearchIndexableResource}
+ *
+ * @param context the context
+ * @return a list of {@link android.provider.SearchIndexableResource} references.
+ * Can be null.
+ */
+ List<SearchIndexableResource> getXmlResourcesToIndex(Context context);
+
+ /**
+ * Return a list of raw data for indexing. See {@link SearchIndexableRaw}
+ *
+ * @param context the context
+ * @return a list of {@link SearchIndexableRaw} references. Can be null.
+ */
+ List<SearchIndexableRaw> getRawDataToIndex(Context context);
+ }
+}
diff --git a/src/com/android/settings/indexer/IndexableData.java b/src/com/android/settings/search/SearchIndexableRaw.java
similarity index 66%
rename from src/com/android/settings/indexer/IndexableData.java
rename to src/com/android/settings/search/SearchIndexableRaw.java
index ca388de..a175be9 100644
--- a/src/com/android/settings/indexer/IndexableData.java
+++ b/src/com/android/settings/search/SearchIndexableRaw.java
@@ -14,32 +14,27 @@
* limitations under the License.
*/
-package com.android.settings.indexer;
+package com.android.settings.search;
-import java.util.Locale;
+import android.content.Context;
+import android.provider.SearchIndexableData;
/**
- * Indexable Data.
+ * Indexable raw data for Search.
*
* This is the raw data used by the Indexer and should match its data model.
*
- * See {@link Indexable} and {@link IndexableRef}.
+ * See {@link Indexable} and {@link android.provider.SearchIndexableResource}.
*/
-public class IndexableData {
-
- public Locale locale;
+public class SearchIndexableRaw extends SearchIndexableData {
public String title;
public String summary;
public String keywords;
- public String intentAction;
- public String intentTargetPackage;
- public String intentTargetClass;
+ public String screenTitle;
- public String fragmentTitle;
-
- public IndexableData() {
- locale = Locale.getDefault();
+ public SearchIndexableRaw(Context context) {
+ super(context);
}
}
diff --git a/src/com/android/settings/search/SettingsSearchIndexablesProvider.java b/src/com/android/settings/search/SettingsSearchIndexablesProvider.java
new file mode 100644
index 0000000..4673572
--- /dev/null
+++ b/src/com/android/settings/search/SettingsSearchIndexablesProvider.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.search;
+
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.provider.SearchIndexableResource;
+import android.provider.SearchIndexablesProvider;
+import com.android.settings.DateTimeSettings;
+import com.android.settings.DevelopmentSettings;
+import com.android.settings.DeviceInfoSettings;
+import com.android.settings.DisplaySettings;
+import com.android.settings.HomeSettings;
+import com.android.settings.PrivacySettings;
+import com.android.settings.R;
+import com.android.settings.SecuritySettings;
+import com.android.settings.SoundSettings;
+import com.android.settings.WallpaperTypeSettings;
+import com.android.settings.WirelessSettings;
+import com.android.settings.accessibility.AccessibilitySettings;
+import com.android.settings.bluetooth.BluetoothSettings;
+import com.android.settings.deviceinfo.Memory;
+import com.android.settings.fuelgauge.PowerUsageSummary;
+import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
+import com.android.settings.location.LocationSettings;
+import com.android.settings.net.DataUsageMeteredSettings;
+import com.android.settings.print.PrintSettingsFragment;
+import com.android.settings.users.UserSettings;
+import com.android.settings.wifi.WifiSettings;
+
+import static android.provider.SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS;
+import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS;
+
+public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider {
+ private static final String TAG = "SettingsSearchIndexablesProvider";
+
+ private static int NO_DATA_RES_ID = 0;
+
+ private static SearchIndexableResource[] INDEXABLE_REFS = new SearchIndexableResource[] {
+ new SearchIndexableResource(1, NO_DATA_RES_ID,
+ WifiSettings.class.getName(),
+ R.drawable.ic_settings_wireless),
+ new SearchIndexableResource(2, R.xml.bluetooth_settings,
+ BluetoothSettings.class.getName(),
+ R.drawable.ic_settings_bluetooth2),
+ new SearchIndexableResource(3, R.xml.data_usage_metered_prefs,
+ DataUsageMeteredSettings.class.getName(),
+ R.drawable.ic_settings_data_usage),
+ new SearchIndexableResource(4, R.xml.wireless_settings,
+ WirelessSettings.class.getName(),
+ R.drawable.empty_icon),
+ new SearchIndexableResource(5, R.xml.home_selection,
+ HomeSettings.class.getName(),
+ R.drawable.ic_settings_home),
+ new SearchIndexableResource(6, R.xml.sound_settings,
+ SoundSettings.class.getName(),
+ R.drawable.ic_settings_sound),
+ new SearchIndexableResource(7, R.xml.display_settings,
+ DisplaySettings.class.getName(),
+ R.drawable.ic_settings_display),
+ new SearchIndexableResource(7, NO_DATA_RES_ID,
+ WallpaperTypeSettings.class.getName(),
+ R.drawable.ic_settings_display),
+ new SearchIndexableResource(8, R.xml.device_info_memory,
+ Memory.class.getName(),
+ R.drawable.ic_settings_storage),
+ new SearchIndexableResource(9, R.xml.power_usage_summary,
+ PowerUsageSummary.class.getName(),
+ R.drawable.ic_settings_battery),
+ new SearchIndexableResource(10, R.xml.user_settings,
+ UserSettings.class.getName(),
+ R.drawable.ic_settings_multiuser),
+ new SearchIndexableResource(11, R.xml.location_settings,
+ LocationSettings.class.getName(),
+ R.drawable.ic_settings_location),
+ new SearchIndexableResource(12, R.xml.security_settings,
+ SecuritySettings.class.getName(),
+ R.drawable.ic_settings_security),
+ new SearchIndexableResource(13, R.xml.language_settings,
+ InputMethodAndLanguageSettings.class.getName(),
+ R.drawable.ic_settings_language),
+ new SearchIndexableResource(14, R.xml.privacy_settings,
+ PrivacySettings.class.getName(),
+ R.drawable.ic_settings_backup),
+ new SearchIndexableResource(15, R.xml.date_time_prefs,
+ DateTimeSettings.class.getName(),
+ R.drawable.ic_settings_date_time),
+ new SearchIndexableResource(16, R.xml.accessibility_settings,
+ AccessibilitySettings.class.getName(),
+ R.drawable.ic_settings_accessibility),
+ new SearchIndexableResource(17, R.xml.print_settings,
+ PrintSettingsFragment.class.getName(),
+ com.android.internal.R.drawable.ic_print),
+ new SearchIndexableResource(18, R.xml.development_prefs,
+ DevelopmentSettings.class.getName(),
+ R.drawable.ic_settings_development),
+ new SearchIndexableResource(19, R.xml.device_info_settings,
+ DeviceInfoSettings.class.getName(),
+ R.drawable.ic_settings_about),
+ };
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public Cursor queryXmlResources(String[] projection) {
+ MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS);
+ final int count = INDEXABLE_REFS.length;
+ for (int n = 0; n < count; n++) {
+ Object[] ref = new Object[7];
+ ref[0] = INDEXABLE_REFS[n].rank;
+ ref[1] = INDEXABLE_REFS[n].xmlResId;
+ ref[2] = INDEXABLE_REFS[n].className;
+ ref[3] = INDEXABLE_REFS[n].iconResId;
+ ref[4] = null; // intent action
+ ref[5] = null; // intent target package
+ ref[6] = null; // intent target class
+ cursor.addRow(ref);
+ }
+ return cursor;
+ }
+
+ @Override
+ public Cursor queryRawData(String[] projection) {
+ Cursor result = new MatrixCursor(INDEXABLES_RAW_COLUMNS);
+ return result;
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index d6e68a3..702d6ae 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -20,12 +20,12 @@
import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
import android.preference.PreferenceActivity;
+import android.provider.SearchIndexableResource;
import com.android.settings.R;
import com.android.settings.RestrictedSettingsFragment;
import com.android.settings.SettingsActivity;
-import com.android.settings.indexer.Indexable;
-import com.android.settings.indexer.IndexableData;
-import com.android.settings.indexer.IndexableRef;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.SearchIndexableRaw;
import com.android.settings.wifi.p2p.WifiP2pSettings;
import android.app.ActionBar;
@@ -1165,22 +1165,22 @@
}
}
- public static final Indexable.IndexDataProvider INDEX_DATA_PROVIDER =
- new Indexable.IndexDataProvider() {
+ public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new SearchIndexProvider() {
@Override
- public List<IndexableRef> getRefsToIndex(Context context) {
+ public List<SearchIndexableResource> getXmlResourcesToIndex(Context context) {
return null;
}
@Override
- public List<IndexableData> getRawDataToIndex(Context context) {
- final List<IndexableData> result = new ArrayList<IndexableData>();
+ public List<SearchIndexableRaw> getRawDataToIndex(Context context) {
+ final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
final Resources res = context.getResources();
// Add fragment title
- IndexableData data = new IndexableData();
+ SearchIndexableRaw data = new SearchIndexableRaw(context);
data.title = res.getString(R.string.wifi_settings);
- data.fragmentTitle = res.getString(R.string.wifi_settings);
+ data.screenTitle = res.getString(R.string.wifi_settings);
result.add(data);
// Add available Wi-Fi access points
@@ -1191,9 +1191,9 @@
for (AccessPoint accessPoint : accessPoints) {
// We are indexing only the saved Wi-Fi networks.
if (accessPoint.getConfig() == null) continue;
- data = new IndexableData();
+ data = new SearchIndexableRaw(context);
data.title = accessPoint.getTitle().toString();
- data.fragmentTitle = res.getString(R.string.wifi_settings);
+ data.screenTitle = res.getString(R.string.wifi_settings);
result.add(data);
}