Add support for saving and using the Preference's key value

- modify the SQlite data model
- update Index code for managing the key value
- pass the key when launching a Fragment or and Activity
- implement a small animation for highlighting the Preference
from a Search result

Change-Id: I617643a4e5e3b752ece8f45ce7d5429037e479da
This commit is contained in:
Fabrice Di Meglio
2014-04-04 19:07:50 -07:00
parent 3586acab85
commit c1457323d2
5 changed files with 100 additions and 19 deletions

View File

@@ -145,6 +145,11 @@ public class SettingsActivity extends Activity
*/ */
public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"; public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args";
/**
* Fragment "key" argument passed thru {@link #EXTRA_SHOW_FRAGMENT_ARGUMENTS}
*/
public static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
/** /**
* When starting this activity, the invoking Intent can contain this extra * When starting this activity, the invoking Intent can contain this extra
* boolean that the header list should not be displayed. This is most often * boolean that the header list should not be displayed. This is most often
@@ -461,6 +466,7 @@ public class SettingsActivity extends Activity
final String initialTitle = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT_TITLE); final String initialTitle = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT_TITLE);
mInitialTitle = (initialTitle != null) ? initialTitle : getTitle(); mInitialTitle = (initialTitle != null) ? initialTitle : getTitle();
setTitle(mInitialTitle); setTitle(mInitialTitle);
switchToFragment( initialFragmentName, initialArguments, true, false, switchToFragment( initialFragmentName, initialArguments, true, false,
mInitialTitle, false); mInitialTitle, false);
} else { } else {

View File

@@ -26,12 +26,15 @@ import android.content.pm.PackageManager;
import android.os.Bundle; import android.os.Bundle;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import android.preference.PreferenceGroupAdapter;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.Button; import android.widget.Button;
import android.widget.ListAdapter;
/** /**
* Base class for Settings fragments, with some helper functions and dialog management. * Base class for Settings fragments, with some helper functions and dialog management.
@@ -41,6 +44,7 @@ public class SettingsPreferenceFragment extends PreferenceFragment implements Di
private static final String TAG = "SettingsPreferenceFragment"; private static final String TAG = "SettingsPreferenceFragment";
private static final int MENU_HELP = Menu.FIRST + 100; private static final int MENU_HELP = Menu.FIRST + 100;
private static final int HIGHLIGHT_DURATION_MILLIS = 750;
private SettingsDialogFragment mDialogFragment; private SettingsDialogFragment mDialogFragment;
@@ -66,6 +70,47 @@ public class SettingsPreferenceFragment extends PreferenceFragment implements Di
if (!TextUtils.isEmpty(mHelpUrl)) { if (!TextUtils.isEmpty(mHelpUrl)) {
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
final Bundle args = getArguments();
if (args != null) {
final String key = args.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY);
final int position = findPositionFromKey(getPreferenceScreen(), key);
if (position >= 0) {
final ListAdapter adapter = getListView().getAdapter();
if (adapter instanceof PreferenceGroupAdapter) {
((PreferenceGroupAdapter) adapter).setActivated(position);
getListView().postDelayed(new Runnable() {
@Override
public void run() {
((PreferenceGroupAdapter) adapter).setActivated(-1);
((PreferenceGroupAdapter) adapter).notifyDataSetChanged();
}
}, HIGHLIGHT_DURATION_MILLIS);
}
}
}
}
private int findPositionFromKey(PreferenceGroup group, String key) {
if (group != null) {
int count = group.getPreferenceCount();
for (int n = 0; n < count; n++) {
final Preference preference = group.getPreference(n);
final String preferenceKey = preference.getKey();
if (preferenceKey != null && preferenceKey.equals(key)) {
return n;
}
if (preference instanceof PreferenceGroup) {
PreferenceGroup nestedGroup = (PreferenceGroup) preference;
final int nestedPosition = findPositionFromKey(nestedGroup, key);
if (nestedPosition >= 0) {
return n + 1 + nestedPosition;
}
}
}
}
return -1;
} }
protected void removePreference(String key) { protected void removePreference(String key) {

View File

@@ -109,15 +109,18 @@ public class SearchResultsSummary extends Fragment {
final String className = cursor.getString(Index.COLUMN_INDEX_CLASS_NAME); final String className = cursor.getString(Index.COLUMN_INDEX_CLASS_NAME);
final String screenTitle = cursor.getString(Index.COLUMN_INDEX_SCREEN_TITLE); final String screenTitle = cursor.getString(Index.COLUMN_INDEX_SCREEN_TITLE);
final String action = cursor.getString(Index.COLUMN_INDEX_INTENT_ACTION); final String action = cursor.getString(Index.COLUMN_INDEX_INTENT_ACTION);
final String key = cursor.getString(Index.COLUMN_INDEX_KEY);
final SettingsActivity sa = (SettingsActivity) getActivity(); final SettingsActivity sa = (SettingsActivity) getActivity();
sa.needToRevertToInitialFragment(); sa.needToRevertToInitialFragment();
if (TextUtils.isEmpty(action)) { if (TextUtils.isEmpty(action)) {
sa.startWithFragment(className, null, null, 0, screenTitle); Bundle args = new Bundle();
args.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, key);
sa.startWithFragment(className, args, null, 0, screenTitle);
} else { } else {
final Intent intent = new Intent(action); final Intent intent = new Intent(action);
@@ -130,6 +133,7 @@ public class SearchResultsSummary extends Fragment {
new ComponentName(targetPackage, targetClass); new ComponentName(targetPackage, targetClass);
intent.setComponent(component); intent.setComponent(component);
} }
intent.putExtra(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, key);
sa.startActivity(intent); sa.startActivity(intent);
} }
@@ -194,21 +198,23 @@ public class SearchResultsSummary extends Fragment {
} }
private static class SearchResult { private static class SearchResult {
public Context context;
public String title; public String title;
public String summaryOn; public String summaryOn;
public String summaryOff; public String summaryOff;
public String entries; public String entries;
public int iconResId; public int iconResId;
public Context context; public String key;
public SearchResult(Context context, String title, String summaryOn, String summaryOff, public SearchResult(Context context, String title, String summaryOn, String summaryOff,
String entries, int iconResId) { String entries, int iconResId, String key) {
this.context = context; this.context = context;
this.title = title; this.title = title;
this.summaryOn = summaryOn; this.summaryOn = summaryOn;
this.summaryOff = summaryOff; this.summaryOff = summaryOff;
this.entries = entries; this.entries = entries;
this.iconResId = iconResId; this.iconResId = iconResId;
this.key = key;
} }
} }
@@ -263,6 +269,8 @@ public class SearchResultsSummary extends Fragment {
Index.COLUMN_INDEX_CLASS_NAME); Index.COLUMN_INDEX_CLASS_NAME);
final String packageName = mCursor.getString( final String packageName = mCursor.getString(
Index.COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE); Index.COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE);
final String key = mCursor.getString(
Index.COLUMN_INDEX_KEY);
Context packageContext; Context packageContext;
if (TextUtils.isEmpty(className) && !TextUtils.isEmpty(packageName)) { if (TextUtils.isEmpty(className) && !TextUtils.isEmpty(packageName)) {
@@ -284,7 +292,7 @@ public class SearchResultsSummary extends Fragment {
R.drawable.empty_icon : Integer.parseInt(iconResStr); R.drawable.empty_icon : Integer.parseInt(iconResStr);
return new SearchResult(packageContext, title, summaryOn, summaryOff, return new SearchResult(packageContext, title, summaryOn, summaryOff,
entries, iconResId); entries, iconResId, key);
} }
return null; return null;
} }

View File

@@ -71,6 +71,7 @@ public class Index {
public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 12; public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 12;
public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 13; public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 13;
public static final int COLUMN_INDEX_ENABLED = 14; public static final int COLUMN_INDEX_ENABLED = 14;
public static final int COLUMN_INDEX_KEY = 15;
// If you change the order of columns here, you SHOULD change the COLUMN_INDEX_XXX values // If you change the order of columns here, you SHOULD change the COLUMN_INDEX_XXX values
private static final String[] SELECT_COLUMNS = new String[] { private static final String[] SELECT_COLUMNS = new String[] {
@@ -87,7 +88,9 @@ public class Index {
IndexColumns.ICON, // 10 IndexColumns.ICON, // 10
IndexColumns.INTENT_ACTION, // 11 IndexColumns.INTENT_ACTION, // 11
IndexColumns.INTENT_TARGET_PACKAGE, // 12 IndexColumns.INTENT_TARGET_PACKAGE, // 12
IndexColumns.INTENT_TARGET_CLASS // 13 IndexColumns.INTENT_TARGET_CLASS, // 13
IndexColumns.ENABLED, // 14
IndexColumns.DATA_KEY_REF // 15
}; };
private static final String[] MATCH_COLUMNS = { private static final String[] MATCH_COLUMNS = {
@@ -375,6 +378,8 @@ public class Index {
final String targetPackage = cursor.getString(12); final String targetPackage = cursor.getString(12);
final String targetClass = cursor.getString(13); final String targetClass = cursor.getString(13);
final String key = cursor.getString(15);
SearchIndexableRaw data = new SearchIndexableRaw(packageContext); SearchIndexableRaw data = new SearchIndexableRaw(packageContext);
data.rank = rank; data.rank = rank;
data.title = title; data.title = title;
@@ -391,6 +396,7 @@ public class Index {
data.intentAction = action; data.intentAction = action;
data.intentTargetPackage = targetPackage; data.intentTargetPackage = targetPackage;
data.intentTargetClass = targetClass; data.intentTargetClass = targetClass;
data.key = key;
addIndexableData(data); addIndexableData(data);
} }
@@ -503,12 +509,13 @@ public class Index {
String title = getDataTitle(context, attrs); String title = getDataTitle(context, attrs);
String summary = getDataSummary(context, attrs); String summary = getDataSummary(context, attrs);
String keywords = getDataKeywords(context, attrs); String keywords = getDataKeywords(context, attrs);
String key = getDataKey(context, attrs);
// Insert rows for the main PreferenceScreen node. Rewrite the data for removing // Insert rows for the main PreferenceScreen node. Rewrite the data for removing
// hyphens. // hyphens.
updateOneRowWithFilteredData(database, localeStr, title, summary, null, null, updateOneRowWithFilteredData(database, localeStr, title, summary, null, null,
null, null, fragmentName, screenTitle, iconResId, rank, keywords, null, null, fragmentName, screenTitle, iconResId, rank,
intentAction, intentTargetPackage, intentTargetClass, true); keywords, intentAction, intentTargetPackage, intentTargetClass, true, key);
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
@@ -520,6 +527,7 @@ public class Index {
title = getDataTitle(context, attrs); title = getDataTitle(context, attrs);
keywords = getDataKeywords(context, attrs); keywords = getDataKeywords(context, attrs);
key = getDataKey(context, attrs);
if (!nodeName.equals(NODE_NAME_CHECK_BOX_PREFERENCE)) { if (!nodeName.equals(NODE_NAME_CHECK_BOX_PREFERENCE)) {
summary = getDataSummary(context, attrs); summary = getDataSummary(context, attrs);
@@ -537,15 +545,17 @@ public class Index {
// Insert rows for the child nodes of PreferenceScreen // Insert rows for the child nodes of PreferenceScreen
updateOneRowWithFilteredData(database, localeStr, title, summary, null, entries, updateOneRowWithFilteredData(database, localeStr, title, summary, null, entries,
switchOn, switchOff, fragmentName, screenTitle, iconResId, rank, keywords, switchOn, switchOff, fragmentName, screenTitle, iconResId, rank,
intentAction, intentTargetPackage, intentTargetClass, true); keywords, intentAction, intentTargetPackage, intentTargetClass,
} else if (nodeName.equals(NODE_NAME_CHECK_BOX_PREFERENCE)) { true, key);
} else {
final String summaryOn = getDataSummaryOn(context, attrs); final String summaryOn = getDataSummaryOn(context, attrs);
final String summaryOff = getDataSummaryOff(context, attrs); final String summaryOff = getDataSummaryOff(context, attrs);
updateOneRowWithFilteredData(database, localeStr, title, summaryOn, summaryOff, updateOneRowWithFilteredData(database, localeStr, title, summaryOn, summaryOff,
null, null, null, fragmentName, screenTitle, iconResId, rank, keywords, null, null, null, fragmentName, screenTitle, iconResId, rank,
intentAction, intentTargetPackage, intentTargetClass, true); keywords, intentAction, intentTargetPackage, intentTargetClass,
true, key);
} }
} }
@@ -580,7 +590,8 @@ public class Index {
raw.intentAction, raw.intentAction,
raw.intentTargetPackage, raw.intentTargetPackage,
raw.intentTargetClass, raw.intentTargetClass,
raw.enabled); raw.enabled,
raw.key);
} }
private void indexFromLocalProvider(SQLiteDatabase database, String localeStr, private void indexFromLocalProvider(SQLiteDatabase database, String localeStr,
@@ -619,7 +630,8 @@ public class Index {
raw.intentAction, raw.intentAction,
raw.intentTargetPackage, raw.intentTargetPackage,
raw.intentTargetClass, raw.intentTargetClass,
raw.enabled); raw.enabled,
raw.key);
} }
} }
@@ -657,7 +669,7 @@ public class Index {
String switchOn, String switchOff, String className, String switchOn, String switchOff, String className,
String screenTitle, int iconResId, int rank, String keywords, String screenTitle, int iconResId, int rank, String keywords,
String intentAction, String intentTargetPackage, String intentTargetClass, String intentAction, String intentTargetPackage, String intentTargetClass,
boolean enabled) { boolean enabled, String key) {
String updatedTitle; String updatedTitle;
if (title != null) { if (title != null) {
@@ -706,7 +718,7 @@ public class Index {
updatedSummaryOff, normalizedSummaryOff, entries, updatedSummaryOff, normalizedSummaryOff, entries,
updatedSwitchOn, normalizedSwitchOn, updatedSwitchOff, normalizedSwitchOff, updatedSwitchOn, normalizedSwitchOn, updatedSwitchOff, normalizedSwitchOff,
className, screenTitle, iconResId, className, screenTitle, iconResId,
rank, keywords, intentAction, intentTargetPackage, intentTargetClass, enabled); rank, keywords, intentAction, intentTargetPackage, intentTargetClass, enabled, key);
} }
private void updateOneRow(SQLiteDatabase database, String locale, private void updateOneRow(SQLiteDatabase database, String locale,
@@ -717,7 +729,7 @@ public class Index {
String updatedSwitchOff, String normalizedSwitchOff, String updatedSwitchOff, String normalizedSwitchOff,
String className, String screenTitle, int iconResId, int rank, String keywords, String className, String screenTitle, int iconResId, int rank, String keywords,
String intentAction, String intentTargetPackage, String intentTargetClass, String intentAction, String intentTargetPackage, String intentTargetClass,
boolean enabled) { boolean enabled, String key) {
if (TextUtils.isEmpty(updatedTitle)) { if (TextUtils.isEmpty(updatedTitle)) {
return; return;
@@ -746,10 +758,17 @@ public class Index {
values.put(IndexColumns.INTENT_TARGET_CLASS, intentTargetClass); values.put(IndexColumns.INTENT_TARGET_CLASS, intentTargetClass);
values.put(IndexColumns.ICON, iconResId); values.put(IndexColumns.ICON, iconResId);
values.put(IndexColumns.ENABLED, enabled); values.put(IndexColumns.ENABLED, enabled);
values.put(IndexColumns.DATA_KEY_REF, key);
database.replaceOrThrow(Tables.TABLE_PREFS_INDEX, null, values); database.replaceOrThrow(Tables.TABLE_PREFS_INDEX, null, values);
} }
private String getDataKey(Context context, AttributeSet attrs) {
return getData(context, attrs,
com.android.internal.R.styleable.Preference,
com.android.internal.R.styleable.Preference_key);
}
private String getDataTitle(Context context, AttributeSet attrs) { private String getDataTitle(Context context, AttributeSet attrs) {
return getData(context, attrs, return getData(context, attrs,
com.android.internal.R.styleable.Preference, com.android.internal.R.styleable.Preference,

View File

@@ -28,7 +28,7 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "IndexDatabaseHelper"; private static final String TAG = "IndexDatabaseHelper";
private static final String DATABASE_NAME = "search_index.db"; private static final String DATABASE_NAME = "search_index.db";
private static final int DATABASE_VERSION = 106; private static final int DATABASE_VERSION = 107;
public interface Tables { public interface Tables {
public static final String TABLE_PREFS_INDEX = "prefs_index"; public static final String TABLE_PREFS_INDEX = "prefs_index";
@@ -58,6 +58,7 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper {
public static final String INTENT_TARGET_CLASS = "intent_target_class"; public static final String INTENT_TARGET_CLASS = "intent_target_class";
public static final String ICON = "icon"; public static final String ICON = "icon";
public static final String ENABLED = "enabled"; public static final String ENABLED = "enabled";
public static final String DATA_KEY_REF = "data_key_reference";
} }
public interface MetaColumns { public interface MetaColumns {
@@ -108,6 +109,8 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper {
IndexColumns.INTENT_TARGET_CLASS + IndexColumns.INTENT_TARGET_CLASS +
", " + ", " +
IndexColumns.ENABLED + IndexColumns.ENABLED +
", " +
IndexColumns.DATA_KEY_REF +
");"; ");";
private static final String CREATE_META_TABLE = private static final String CREATE_META_TABLE =