Add dynamic Preferences indexing
- introduce a new private interface "Indexable". - refactor Wallpaper and Wi-Fi settings to support this new interface. - only index saved/remembered Wi-Fi networks - also add the capability to remove some data from the Index. Fragments that want to publish some dynamic indexable data should implement the "Indexable" interface and provide a static final field named "INDEX_DATA_PROVIDER" with is the Indexable.IndexDataProvider interface for providing the data for indexing. Thru this interface the Index can ask what are the data chuncks to index. Change-Id: I31e7212c87b8218efe1a8f3028147cb19e119be6
This commit is contained in:
@@ -95,7 +95,7 @@ import com.android.settings.deviceinfo.Memory;
|
|||||||
import com.android.settings.deviceinfo.UsbSettings;
|
import com.android.settings.deviceinfo.UsbSettings;
|
||||||
import com.android.settings.fuelgauge.PowerUsageSummary;
|
import com.android.settings.fuelgauge.PowerUsageSummary;
|
||||||
import com.android.settings.indexer.Index;
|
import com.android.settings.indexer.Index;
|
||||||
import com.android.settings.indexer.IndexableData;
|
import com.android.settings.indexer.IndexableRef;
|
||||||
import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
|
import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
|
||||||
import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
|
import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
|
||||||
import com.android.settings.inputmethod.SpellCheckersSettings;
|
import com.android.settings.inputmethod.SpellCheckersSettings;
|
||||||
@@ -341,67 +341,72 @@ public class SettingsActivity extends Activity
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static int NO_DATA_RES_ID = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searchable data description.
|
* Indexable data description.
|
||||||
*
|
*
|
||||||
* Known restriction: we are only searching (for now) the first level of Settings.
|
* Known restriction: we are only searching (for now) the first level of Settings.
|
||||||
*/
|
*/
|
||||||
private static IndexableData[] INDEXABLE_DATA = new IndexableData[] {
|
private static IndexableRef[] INDEXABLE_REFS = new IndexableRef[] {
|
||||||
new IndexableData(1, R.xml.wifi_settings,
|
new IndexableRef(1, NO_DATA_RES_ID,
|
||||||
"com.android.settings.wifi.WifiSettings",
|
"com.android.settings.wifi.WifiSettings",
|
||||||
R.drawable.ic_settings_wireless),
|
R.drawable.ic_settings_wireless),
|
||||||
new IndexableData(2, R.xml.bluetooth_settings,
|
new IndexableRef(2, R.xml.bluetooth_settings,
|
||||||
"com.android.settings.bluetooth.BluetoothSettings",
|
"com.android.settings.bluetooth.BluetoothSettings",
|
||||||
R.drawable.ic_settings_bluetooth2),
|
R.drawable.ic_settings_bluetooth2),
|
||||||
new IndexableData(3, R.xml.data_usage_metered_prefs,
|
new IndexableRef(3, R.xml.data_usage_metered_prefs,
|
||||||
"com.android.settings.net.DataUsageMeteredSettings",
|
"com.android.settings.net.DataUsageMeteredSettings",
|
||||||
R.drawable.ic_settings_data_usage),
|
R.drawable.ic_settings_data_usage),
|
||||||
new IndexableData(4, R.xml.wireless_settings,
|
new IndexableRef(4, R.xml.wireless_settings,
|
||||||
"com.android.settings.WirelessSettings",
|
"com.android.settings.WirelessSettings",
|
||||||
R.drawable.empty_icon),
|
R.drawable.empty_icon),
|
||||||
new IndexableData(5, R.xml.home_selection,
|
new IndexableRef(5, R.xml.home_selection,
|
||||||
"com.android.settings.HomeSettings",
|
"com.android.settings.HomeSettings",
|
||||||
R.drawable.ic_settings_home),
|
R.drawable.ic_settings_home),
|
||||||
new IndexableData(6, R.xml.sound_settings,
|
new IndexableRef(6, R.xml.sound_settings,
|
||||||
"com.android.settings.SoundSettings",
|
"com.android.settings.SoundSettings",
|
||||||
R.drawable.ic_settings_sound),
|
R.drawable.ic_settings_sound),
|
||||||
new IndexableData(7, R.xml.display_settings,
|
new IndexableRef(7, R.xml.display_settings,
|
||||||
"com.android.settings.DisplaySettings",
|
"com.android.settings.DisplaySettings",
|
||||||
R.drawable.ic_settings_display),
|
R.drawable.ic_settings_display),
|
||||||
new IndexableData(8, R.xml.device_info_memory,
|
new IndexableRef(7, NO_DATA_RES_ID,
|
||||||
|
"com.android.settings.WallpaperTypeSettings",
|
||||||
|
R.drawable.ic_settings_display),
|
||||||
|
new IndexableRef(8, R.xml.device_info_memory,
|
||||||
"com.android.settings.deviceinfo.Memory",
|
"com.android.settings.deviceinfo.Memory",
|
||||||
R.drawable.ic_settings_storage),
|
R.drawable.ic_settings_storage),
|
||||||
new IndexableData(9, R.xml.power_usage_summary,
|
new IndexableRef(9, R.xml.power_usage_summary,
|
||||||
"com.android.settings.fuelgauge.PowerUsageSummary",
|
"com.android.settings.fuelgauge.PowerUsageSummary",
|
||||||
R.drawable.ic_settings_battery),
|
R.drawable.ic_settings_battery),
|
||||||
new IndexableData(10, R.xml.user_settings,
|
new IndexableRef(10, R.xml.user_settings,
|
||||||
"com.android.settings.users.UserSettings",
|
"com.android.settings.users.UserSettings",
|
||||||
R.drawable.ic_settings_multiuser),
|
R.drawable.ic_settings_multiuser),
|
||||||
new IndexableData(11, R.xml.location_settings,
|
new IndexableRef(11, R.xml.location_settings,
|
||||||
"com.android.settings.location.LocationSettings",
|
"com.android.settings.location.LocationSettings",
|
||||||
R.drawable.ic_settings_location),
|
R.drawable.ic_settings_location),
|
||||||
new IndexableData(12, R.xml.security_settings,
|
new IndexableRef(12, R.xml.security_settings,
|
||||||
"com.android.settings.SecuritySettings",
|
"com.android.settings.SecuritySettings",
|
||||||
R.drawable.ic_settings_security),
|
R.drawable.ic_settings_security),
|
||||||
new IndexableData(13, R.xml.language_settings,
|
new IndexableRef(13, R.xml.language_settings,
|
||||||
"com.android.settings.inputmethod.InputMethodAndLanguageSettings",
|
"com.android.settings.inputmethod.InputMethodAndLanguageSettings",
|
||||||
R.drawable.ic_settings_language),
|
R.drawable.ic_settings_language),
|
||||||
new IndexableData(14, R.xml.privacy_settings,
|
new IndexableRef(14, R.xml.privacy_settings,
|
||||||
"com.android.settings.PrivacySettings",
|
"com.android.settings.PrivacySettings",
|
||||||
R.drawable.ic_settings_backup),
|
R.drawable.ic_settings_backup),
|
||||||
new IndexableData(15, R.xml.date_time_prefs,
|
new IndexableRef(15, R.xml.date_time_prefs,
|
||||||
"com.android.settings.DateTimeSettings",
|
"com.android.settings.DateTimeSettings",
|
||||||
R.drawable.ic_settings_date_time),
|
R.drawable.ic_settings_date_time),
|
||||||
new IndexableData(16, R.xml.accessibility_settings,
|
new IndexableRef(16, R.xml.accessibility_settings,
|
||||||
"com.android.settings.accessibility.AccessibilitySettings",
|
"com.android.settings.accessibility.AccessibilitySettings",
|
||||||
R.drawable.ic_settings_accessibility),
|
R.drawable.ic_settings_accessibility),
|
||||||
new IndexableData(17, R.xml.print_settings,
|
new IndexableRef(17, R.xml.print_settings,
|
||||||
"com.android.settings.print.PrintSettingsFragment",
|
"com.android.settings.print.PrintSettingsFragment",
|
||||||
com.android.internal.R.drawable.ic_print),
|
com.android.internal.R.drawable.ic_print),
|
||||||
new IndexableData(18, R.xml.development_prefs,
|
new IndexableRef(18, R.xml.development_prefs,
|
||||||
"com.android.settings.DevelopmentSettings",
|
"com.android.settings.DevelopmentSettings",
|
||||||
R.drawable.ic_settings_development),
|
R.drawable.ic_settings_development),
|
||||||
new IndexableData(19, R.xml.device_info_settings,
|
new IndexableRef(19, R.xml.device_info_settings,
|
||||||
"com.android.settings.DeviceInfoSettings",
|
"com.android.settings.DeviceInfoSettings",
|
||||||
R.drawable.ic_settings_about),
|
R.drawable.ic_settings_about),
|
||||||
};
|
};
|
||||||
@@ -546,7 +551,7 @@ public class SettingsActivity extends Activity
|
|||||||
getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
|
getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
Index.getInstance(this).addIndexableData(INDEXABLE_DATA);
|
Index.getInstance(this).addIndexableData(INDEXABLE_REFS);
|
||||||
Index.getInstance(this).update();
|
Index.getInstance(this).update();
|
||||||
|
|
||||||
mAuthenticatorHelper = new AuthenticatorHelper();
|
mAuthenticatorHelper = new AuthenticatorHelper();
|
||||||
|
@@ -16,18 +16,23 @@
|
|||||||
|
|
||||||
package com.android.settings;
|
package com.android.settings;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
|
import com.android.settings.indexer.Indexable;
|
||||||
|
import com.android.settings.indexer.IndexableData;
|
||||||
|
import com.android.settings.indexer.IndexableRef;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class WallpaperTypeSettings extends SettingsPreferenceFragment {
|
public class WallpaperTypeSettings extends SettingsPreferenceFragment implements Indexable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -38,9 +43,9 @@ public class WallpaperTypeSettings extends SettingsPreferenceFragment {
|
|||||||
|
|
||||||
private void populateWallpaperTypes() {
|
private void populateWallpaperTypes() {
|
||||||
// Search for activities that satisfy the ACTION_SET_WALLPAPER action
|
// Search for activities that satisfy the ACTION_SET_WALLPAPER action
|
||||||
Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER);
|
final Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER);
|
||||||
final PackageManager pm = getPackageManager();
|
final PackageManager pm = getPackageManager();
|
||||||
List<ResolveInfo> rList = pm.queryIntentActivities(intent,
|
final List<ResolveInfo> rList = pm.queryIntentActivities(intent,
|
||||||
PackageManager.MATCH_DEFAULT_ONLY);
|
PackageManager.MATCH_DEFAULT_ONLY);
|
||||||
|
|
||||||
final PreferenceScreen parent = getPreferenceScreen();
|
final PreferenceScreen parent = getPreferenceScreen();
|
||||||
@@ -58,4 +63,42 @@ public class WallpaperTypeSettings extends SettingsPreferenceFragment {
|
|||||||
parent.addPreference(pref);
|
parent.addPreference(pref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final IndexDataProvider INDEX_DATA_PROVIDER =
|
||||||
|
new IndexDataProvider() {
|
||||||
|
@Override
|
||||||
|
public List<IndexableRef> getRefsToIndex(Context context) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<IndexableData> getRawDataToIndex(Context context) {
|
||||||
|
final List<IndexableData> result = new ArrayList<IndexableData>();
|
||||||
|
|
||||||
|
final Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER);
|
||||||
|
final PackageManager pm = context.getPackageManager();
|
||||||
|
final List<ResolveInfo> rList = pm.queryIntentActivities(intent,
|
||||||
|
PackageManager.MATCH_DEFAULT_ONLY);
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
data.title = label.toString();
|
||||||
|
data.fragmentTitle = context.getResources().getString(
|
||||||
|
R.string.wallpaper_settings_fragment_title);
|
||||||
|
data.intentAction = intent.getAction();
|
||||||
|
data.intentTargetPackage = info.activityInfo.packageName;
|
||||||
|
data.intentTargetClass = info.activityInfo.name;
|
||||||
|
result.add(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -34,6 +34,7 @@ import org.xmlpull.v1.XmlPullParser;
|
|||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -45,7 +46,7 @@ import static com.android.settings.indexer.IndexDatabaseHelper.IndexColumns;
|
|||||||
|
|
||||||
public class Index {
|
public class Index {
|
||||||
|
|
||||||
private static final String LOG_TAG = "Indexer";
|
private static final String LOG_TAG = "Index";
|
||||||
|
|
||||||
// Those indices should match the indices of SELECT_COLUMNS !
|
// Those indices should match the indices of SELECT_COLUMNS !
|
||||||
public static final int COLUMN_INDEX_TITLE = 1;
|
public static final int COLUMN_INDEX_TITLE = 1;
|
||||||
@@ -81,7 +82,8 @@ public class Index {
|
|||||||
private static Index sInstance;
|
private static Index sInstance;
|
||||||
|
|
||||||
private final AtomicBoolean mIsAvailable = new AtomicBoolean(false);
|
private final AtomicBoolean mIsAvailable = new AtomicBoolean(false);
|
||||||
private final List<IndexableData> mDataToIndex = new ArrayList<IndexableData>();
|
|
||||||
|
private final UpdateData mUpdateData = new UpdateData();
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
|
|
||||||
@@ -103,6 +105,42 @@ public class Index {
|
|||||||
return mIsAvailable.get();
|
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) {
|
public Cursor search(String query) {
|
||||||
final String sql = buildSQL(query);
|
final String sql = buildSQL(query);
|
||||||
Log.d(LOG_TAG, "Query: " + sql);
|
Log.d(LOG_TAG, "Query: " + sql);
|
||||||
@@ -160,31 +198,6 @@ public class Index {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addIndexableData(IndexableData[] array) {
|
|
||||||
synchronized (mDataToIndex) {
|
|
||||||
final int count = array.length;
|
|
||||||
for (int n = 0; n < count; n++) {
|
|
||||||
mDataToIndex.add(array[n]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean update() {
|
|
||||||
synchronized (mDataToIndex) {
|
|
||||||
final IndexTask task = new IndexTask();
|
|
||||||
task.execute(mDataToIndex);
|
|
||||||
try {
|
|
||||||
return task.get();
|
|
||||||
} 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private SQLiteDatabase getReadableDatabase() {
|
private SQLiteDatabase getReadableDatabase() {
|
||||||
return IndexDatabaseHelper.getInstance(mContext).getReadableDatabase();
|
return IndexDatabaseHelper.getInstance(mContext).getReadableDatabase();
|
||||||
}
|
}
|
||||||
@@ -193,10 +206,28 @@ public class Index {
|
|||||||
return IndexDatabaseHelper.getInstance(mContext).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
|
* A private class for updating the Index database
|
||||||
*/
|
*/
|
||||||
private class IndexTask extends AsyncTask<List<IndexableData>, Integer, Boolean> {
|
private class UpdateIndexTask extends AsyncTask<UpdateData, Integer, Boolean> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPreExecute() {
|
protected void onPreExecute() {
|
||||||
@@ -211,45 +242,123 @@ public class Index {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground(List<IndexableData>... params) {
|
protected Boolean doInBackground(UpdateData... params) {
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
final List<IndexableData> dataToIndex = params[0];
|
|
||||||
if (null == dataToIndex || dataToIndex.size() == 0) {
|
final List<IndexableRef> dataToAdd = params[0].dataToAdd;
|
||||||
return result;
|
final List<String> dataToDelete = params[0].dataToDelete;
|
||||||
}
|
|
||||||
final SQLiteDatabase database = getWritableDatabase();
|
final SQLiteDatabase database = getWritableDatabase();
|
||||||
final Locale locale = Locale.getDefault();
|
final String localeStr = Locale.getDefault().toString();
|
||||||
final String localeStr = locale.toString();
|
|
||||||
if (isLocaleAlreadyIndexed(database, locale)) {
|
|
||||||
Log.d(LOG_TAG, "Locale '" + localeStr + "' is already indexed");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
final long current = System.currentTimeMillis();
|
|
||||||
try {
|
try {
|
||||||
database.beginTransaction();
|
database.beginTransaction();
|
||||||
final int count = mDataToIndex.size();
|
if (dataToAdd.size() > 0) {
|
||||||
for (int n = 0; n < count; n++) {
|
processDataToAdd(database, localeStr, dataToAdd);
|
||||||
final IndexableData data = mDataToIndex.get(n);
|
}
|
||||||
indexFromResource(database, locale, data.xmlResId, data.fragmentName,
|
if (dataToDelete.size() > 0) {
|
||||||
data.iconResId, data.rank);
|
processDataToDelete(database, localeStr, dataToDelete);
|
||||||
}
|
}
|
||||||
database.setTransactionSuccessful();
|
database.setTransactionSuccessful();
|
||||||
result = true;
|
result = true;
|
||||||
} finally {
|
} finally {
|
||||||
database.endTransaction();
|
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();
|
final long now = System.currentTimeMillis();
|
||||||
Log.d(LOG_TAG, "Indexing locale '" + localeStr + "' took " +
|
Log.d(LOG_TAG, "Indexing locale '" + localeStr + "' took " +
|
||||||
(now - current) + " millis");
|
(now - current) + " millis");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isLocaleAlreadyIndexed(SQLiteDatabase database, Locale locale) {
|
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;
|
Cursor cursor = null;
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
final StringBuilder sb = new StringBuilder(IndexColumns.LOCALE);
|
final StringBuilder sb = new StringBuilder(IndexColumns.LOCALE);
|
||||||
sb.append(" = ");
|
sb.append(" = ");
|
||||||
DatabaseUtils.appendEscapedSQLString(sb, locale.toString());
|
DatabaseUtils.appendEscapedSQLString(sb, locale);
|
||||||
try {
|
try {
|
||||||
// We care only for 1 row
|
// We care only for 1 row
|
||||||
cursor = database.query(Tables.TABLE_PREFS_INDEX, null,
|
cursor = database.query(Tables.TABLE_PREFS_INDEX, null,
|
||||||
@@ -264,10 +373,9 @@ public class Index {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void indexFromResource(SQLiteDatabase database, Locale locale, int xmlResId,
|
private void indexFromResource(SQLiteDatabase database, String localeStr, int xmlResId,
|
||||||
String fragmentName, int iconResId, int rank) {
|
String fragmentName, int iconResId, int rank) {
|
||||||
XmlResourceParser parser = null;
|
XmlResourceParser parser = null;
|
||||||
final String localeStr = locale.toString();
|
|
||||||
try {
|
try {
|
||||||
parser = mContext.getResources().getXml(xmlResId);
|
parser = mContext.getResources().getXml(xmlResId);
|
||||||
|
|
||||||
@@ -373,6 +481,13 @@ public class Index {
|
|||||||
database.insertOrThrow(Tables.TABLE_PREFS_INDEX, null, values);
|
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) {
|
private String getDataTitle(AttributeSet attrs) {
|
||||||
return getData(attrs,
|
return getData(attrs,
|
||||||
com.android.internal.R.styleable.Preference,
|
com.android.internal.R.styleable.Preference,
|
||||||
|
52
src/com/android/settings/indexer/Indexable.java
Normal file
52
src/com/android/settings/indexer/Indexable.java
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
@@ -16,17 +16,30 @@
|
|||||||
|
|
||||||
package com.android.settings.indexer;
|
package com.android.settings.indexer;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indexable Data.
|
||||||
|
*
|
||||||
|
* This is the raw data used by the Indexer and should match its data model.
|
||||||
|
*
|
||||||
|
* See {@link Indexable} and {@link IndexableRef}.
|
||||||
|
*/
|
||||||
public class IndexableData {
|
public class IndexableData {
|
||||||
|
|
||||||
public int rank;
|
public Locale locale;
|
||||||
public int xmlResId;
|
|
||||||
public String fragmentName;
|
|
||||||
public int iconResId;
|
|
||||||
|
|
||||||
public IndexableData(int rank, int dataResId, String name, int iconResId) {
|
public String title;
|
||||||
this.rank = rank;
|
public String summary;
|
||||||
this.xmlResId = dataResId;
|
public String keywords;
|
||||||
this.fragmentName = name;
|
|
||||||
this.iconResId = iconResId;
|
public String intentAction;
|
||||||
|
public String intentTargetPackage;
|
||||||
|
public String intentTargetClass;
|
||||||
|
|
||||||
|
public String fragmentTitle;
|
||||||
|
|
||||||
|
public IndexableData() {
|
||||||
|
locale = Locale.getDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
46
src/com/android/settings/indexer/IndexableRef.java
Normal file
46
src/com/android/settings/indexer/IndexableRef.java
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
@@ -23,6 +23,9 @@ import android.preference.PreferenceActivity;
|
|||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.RestrictedSettingsFragment;
|
import com.android.settings.RestrictedSettingsFragment;
|
||||||
import com.android.settings.SettingsActivity;
|
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.wifi.p2p.WifiP2pSettings;
|
import com.android.settings.wifi.p2p.WifiP2pSettings;
|
||||||
|
|
||||||
import android.app.ActionBar;
|
import android.app.ActionBar;
|
||||||
@@ -90,7 +93,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
* and menus.
|
* and menus.
|
||||||
*/
|
*/
|
||||||
public class WifiSettings extends RestrictedSettingsFragment
|
public class WifiSettings extends RestrictedSettingsFragment
|
||||||
implements DialogInterface.OnClickListener {
|
implements DialogInterface.OnClickListener, Indexable {
|
||||||
private static final String TAG = "WifiSettings";
|
private static final String TAG = "WifiSettings";
|
||||||
private static final int MENU_ID_WPS_PBC = Menu.FIRST;
|
private static final int MENU_ID_WPS_PBC = Menu.FIRST;
|
||||||
private static final int MENU_ID_WPS_PIN = Menu.FIRST + 1;
|
private static final int MENU_ID_WPS_PIN = Menu.FIRST + 1;
|
||||||
@@ -742,7 +745,8 @@ public class WifiSettings extends RestrictedSettingsFragment
|
|||||||
switch (wifiState) {
|
switch (wifiState) {
|
||||||
case WifiManager.WIFI_STATE_ENABLED:
|
case WifiManager.WIFI_STATE_ENABLED:
|
||||||
// AccessPoints are automatically sorted with TreeSet.
|
// AccessPoints are automatically sorted with TreeSet.
|
||||||
final Collection<AccessPoint> accessPoints = constructAccessPoints();
|
final Collection<AccessPoint> accessPoints =
|
||||||
|
constructAccessPoints(getActivity(), mWifiManager, mLastInfo, mLastState);
|
||||||
getPreferenceScreen().removeAll();
|
getPreferenceScreen().removeAll();
|
||||||
if(accessPoints.size() == 0) {
|
if(accessPoints.size() == 0) {
|
||||||
addMessagePreference(R.string.wifi_empty_list_wifi_on);
|
addMessagePreference(R.string.wifi_empty_list_wifi_on);
|
||||||
@@ -792,23 +796,26 @@ public class WifiSettings extends RestrictedSettingsFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Returns sorted list of access points */
|
/** Returns sorted list of access points */
|
||||||
private List<AccessPoint> constructAccessPoints() {
|
private static List<AccessPoint> constructAccessPoints(Context context,
|
||||||
|
WifiManager wifiManager, WifiInfo lastInfo, DetailedState lastState) {
|
||||||
ArrayList<AccessPoint> accessPoints = new ArrayList<AccessPoint>();
|
ArrayList<AccessPoint> accessPoints = new ArrayList<AccessPoint>();
|
||||||
/** Lookup table to more quickly update AccessPoints by only considering objects with the
|
/** Lookup table to more quickly update AccessPoints by only considering objects with the
|
||||||
* correct SSID. Maps SSID -> List of AccessPoints with the given SSID. */
|
* correct SSID. Maps SSID -> List of AccessPoints with the given SSID. */
|
||||||
Multimap<String, AccessPoint> apMap = new Multimap<String, AccessPoint>();
|
Multimap<String, AccessPoint> apMap = new Multimap<String, AccessPoint>();
|
||||||
|
|
||||||
final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
|
final List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks();
|
||||||
if (configs != null) {
|
if (configs != null) {
|
||||||
for (WifiConfiguration config : configs) {
|
for (WifiConfiguration config : configs) {
|
||||||
AccessPoint accessPoint = new AccessPoint(getActivity(), config);
|
AccessPoint accessPoint = new AccessPoint(context, config);
|
||||||
accessPoint.update(mLastInfo, mLastState);
|
if (lastInfo != null && lastState != null) {
|
||||||
|
accessPoint.update(lastInfo, lastState);
|
||||||
|
}
|
||||||
accessPoints.add(accessPoint);
|
accessPoints.add(accessPoint);
|
||||||
apMap.put(accessPoint.ssid, accessPoint);
|
apMap.put(accessPoint.ssid, accessPoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<ScanResult> results = mWifiManager.getScanResults();
|
final List<ScanResult> results = wifiManager.getScanResults();
|
||||||
if (results != null) {
|
if (results != null) {
|
||||||
for (ScanResult result : results) {
|
for (ScanResult result : results) {
|
||||||
// Ignore hidden and ad-hoc networks.
|
// Ignore hidden and ad-hoc networks.
|
||||||
@@ -823,7 +830,7 @@ public class WifiSettings extends RestrictedSettingsFragment
|
|||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
AccessPoint accessPoint = new AccessPoint(getActivity(), result);
|
AccessPoint accessPoint = new AccessPoint(context, result);
|
||||||
accessPoints.add(accessPoint);
|
accessPoints.add(accessPoint);
|
||||||
apMap.put(accessPoint.ssid, accessPoint);
|
apMap.put(accessPoint.ssid, accessPoint);
|
||||||
}
|
}
|
||||||
@@ -836,7 +843,7 @@ public class WifiSettings extends RestrictedSettingsFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A restricted multimap for use in constructAccessPoints */
|
/** A restricted multimap for use in constructAccessPoints */
|
||||||
private class Multimap<K,V> {
|
private static class Multimap<K,V> {
|
||||||
private final HashMap<K,List<V>> store = new HashMap<K,List<V>>();
|
private final HashMap<K,List<V>> store = new HashMap<K,List<V>>();
|
||||||
/** retrieve a non-null list of values with key K */
|
/** retrieve a non-null list of values with key K */
|
||||||
List<V> getAll(K key) {
|
List<V> getAll(K key) {
|
||||||
@@ -1152,4 +1159,38 @@ public class WifiSettings extends RestrictedSettingsFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final Indexable.IndexDataProvider INDEX_DATA_PROVIDER =
|
||||||
|
new Indexable.IndexDataProvider() {
|
||||||
|
@Override
|
||||||
|
public List<IndexableRef> getRefsToIndex(Context context) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<IndexableData> getRawDataToIndex(Context context) {
|
||||||
|
final List<IndexableData> result = new ArrayList<IndexableData>();
|
||||||
|
|
||||||
|
// Add fragment title
|
||||||
|
IndexableData data = new IndexableData();
|
||||||
|
data.title = context.getResources().getString(R.string.wifi_settings);
|
||||||
|
data.fragmentTitle = context.getResources().getString(R.string.wifi_settings);
|
||||||
|
result.add(data);
|
||||||
|
|
||||||
|
// Add available Wi-Fi access points
|
||||||
|
WifiManager wifiManager =
|
||||||
|
(WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
||||||
|
final Collection<AccessPoint> accessPoints =
|
||||||
|
constructAccessPoints(context, wifiManager, null, null);
|
||||||
|
for (AccessPoint accessPoint : accessPoints) {
|
||||||
|
// We are indexing only the saved Wi-Fi networks.
|
||||||
|
if (accessPoint.getConfig() == null) continue;
|
||||||
|
data = new IndexableData();
|
||||||
|
data.title = accessPoint.getTitle().toString();
|
||||||
|
data.fragmentTitle = context.getResources().getString(R.string.wifi_settings);
|
||||||
|
result.add(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user