Merge "Add dynamic Preferences indexing"

This commit is contained in:
Fabrice Di Meglio
2014-03-12 19:58:05 +00:00
committed by Android (Google) Code Review
7 changed files with 410 additions and 95 deletions

View File

@@ -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();

View File

@@ -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;
}
};
} }

View File

@@ -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,

View 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);
}
}

View File

@@ -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();
} }
} }

View 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;
}
}

View File

@@ -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;
@@ -748,7 +751,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);
@@ -798,23 +802,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.
@@ -829,7 +836,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);
} }
@@ -842,7 +849,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) {
@@ -1158,4 +1165,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;
}
};
} }