Add indexing for ListPreferences

- now support ListPreferences and save the "entries" attribute
- update Index database schema (and increment its version)
- do some clever stuff when showing Search results: if there is
a "$s" or "%s" in the summary (replacement strings), just use
the entries instead

Change-Id: If36595c3816706b6349faff7d3c2e725d3ea33f4
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 206865f..5aa2737 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -24,7 +24,6 @@
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
-import android.app.SearchManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
diff --git a/src/com/android/settings/dashboard/SearchResultsSummary.java b/src/com/android/settings/dashboard/SearchResultsSummary.java
index 41d8609..706ae0f 100644
--- a/src/com/android/settings/dashboard/SearchResultsSummary.java
+++ b/src/com/android/settings/dashboard/SearchResultsSummary.java
@@ -197,15 +197,17 @@
         public String title;
         public String summaryOn;
         public String summaryOff;
+        public String entries;
         public int iconResId;
         public Context context;
 
         public SearchResult(Context context, String title, String summaryOn, String summaryOff,
-                int iconResId) {
+                String entries, int iconResId) {
             this.context = context;
             this.title = title;
             this.summaryOn = summaryOn;
             this.summaryOff = summaryOff;
+            this.entries = entries;
             this.iconResId = iconResId;
         }
     }
@@ -218,6 +220,9 @@
         private Context mContext;
         private HashMap<String, Context> mContextMap = new HashMap<String, Context>();
 
+        private static final String PERCENT_RECLACE = "%s";
+        private static final String DOLLAR_REPLACE = "$s";
+
         public SearchResultsAdapter(Context context) {
             mContext = context;
             mInflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -252,6 +257,7 @@
                 final String title = mCursor.getString(Index.COLUMN_INDEX_TITLE);
                 final String summaryOn = mCursor.getString(Index.COLUMN_INDEX_SUMMARY_ON);
                 final String summaryOff = mCursor.getString(Index.COLUMN_INDEX_SUMMARY_OFF);
+                final String entries = mCursor.getString(Index.COLUMN_INDEX_ENTRIES);
                 final String iconResStr = mCursor.getString(Index.COLUMN_INDEX_ICON);
                 final String className = mCursor.getString(
                         Index.COLUMN_INDEX_CLASS_NAME);
@@ -273,9 +279,12 @@
                 } else {
                     packageContext = mContext;
                 }
+
                 final int iconResId = TextUtils.isEmpty(iconResStr) ?
                         R.drawable.empty_icon : Integer.parseInt(iconResStr);
-                return new SearchResult(packageContext, title, summaryOn, summaryOff, iconResId);
+
+                return new SearchResult(packageContext, title, summaryOn, summaryOff,
+                        entries, iconResId);
             }
             return null;
         }
@@ -312,10 +321,26 @@
             SearchResult result = (SearchResult) getItem(position);
 
             textTitle.setText(result.title);
-            final StringBuilder sb = new StringBuilder(result.summaryOn);
-            if (!TextUtils.isEmpty(result.summaryOff)) {
-                sb.append(" | ");
-                sb.append(result.summaryOff);
+
+            String summaryOn = result.summaryOn;
+            String summaryOff = result.summaryOff;
+            String entries = result.entries;
+
+            final StringBuilder sb = new StringBuilder();
+
+            if (!TextUtils.isEmpty(summaryOn) &&
+                    !summaryOn.contains(PERCENT_RECLACE) && !summaryOn.contains(DOLLAR_REPLACE)) {
+                sb.append(summaryOn);
+                if (!TextUtils.isEmpty(summaryOff) &&
+                        !summaryOff.contains(PERCENT_RECLACE) &&
+                        !summaryOff.contains(DOLLAR_REPLACE)) {
+                    sb.append(" \n ");
+                    sb.append(summaryOff);
+                }
+            }
+            if (!TextUtils.isEmpty(entries)) {
+                sb.append(" \n ");
+                sb.append(entries);
             }
             textSummary.setText(sb.toString());
             if (result.iconResId != R.drawable.empty_icon) {
diff --git a/src/com/android/settings/search/Index.java b/src/com/android/settings/search/Index.java
index bfeedc9..246e8a0 100644
--- a/src/com/android/settings/search/Index.java
+++ b/src/com/android/settings/search/Index.java
@@ -60,14 +60,15 @@
     public static final int COLUMN_INDEX_TITLE = 1;
     public static final int COLUMN_INDEX_SUMMARY_ON = 2;
     public static final int COLUMN_INDEX_SUMMARY_OFF = 3;
-    public static final int COLUMN_INDEX_KEYWORDS = 4;
-    public static final int COLUMN_INDEX_CLASS_NAME = 5;
-    public static final int COLUMN_INDEX_SCREEN_TITLE = 6;
-    public static final int COLUMN_INDEX_ICON = 7;
-    public static final int COLUMN_INDEX_INTENT_ACTION = 8;
-    public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 9;
-    public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 10;
-    public static final int COLUMN_INDEX_ENABLED = 11;
+    public static final int COLUMN_INDEX_ENTRIES = 4;
+    public static final int COLUMN_INDEX_KEYWORDS = 5;
+    public static final int COLUMN_INDEX_CLASS_NAME = 6;
+    public static final int COLUMN_INDEX_SCREEN_TITLE = 7;
+    public static final int COLUMN_INDEX_ICON = 8;
+    public static final int COLUMN_INDEX_INTENT_ACTION = 9;
+    public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 10;
+    public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 11;
+    public static final int COLUMN_INDEX_ENABLED = 12;
 
     // If you change the order of columns here, you SHOULD change the COLUMN_INDEX_XXX values
     private static final String[] SELECT_COLUMNS = new String[] {
@@ -75,13 +76,14 @@
             IndexColumns.DATA_TITLE,              // 1
             IndexColumns.DATA_SUMMARY_ON,         // 2
             IndexColumns.DATA_SUMMARY_OFF,        // 3
-            IndexColumns.DATA_KEYWORDS,           // 4
-            IndexColumns.CLASS_NAME,              // 5
-            IndexColumns.SCREEN_TITLE,            // 6
-            IndexColumns.ICON,                    // 7
-            IndexColumns.INTENT_ACTION,           // 8
-            IndexColumns.INTENT_TARGET_PACKAGE,   // 9
-            IndexColumns.INTENT_TARGET_CLASS      // 10
+            IndexColumns.DATA_ENTRIES,            // 4
+            IndexColumns.DATA_KEYWORDS,           // 5
+            IndexColumns.CLASS_NAME,              // 6
+            IndexColumns.SCREEN_TITLE,            // 7
+            IndexColumns.ICON,                    // 8
+            IndexColumns.INTENT_ACTION,           // 9
+            IndexColumns.INTENT_TARGET_PACKAGE,   // 10
+            IndexColumns.INTENT_TARGET_CLASS      // 11
     };
 
     private static final String[] MATCH_COLUMNS = {
@@ -91,6 +93,7 @@
             IndexColumns.DATA_SUMMARY_ON_NORMALIZED,
             IndexColumns.DATA_SUMMARY_OFF,
             IndexColumns.DATA_SUMMARY_OFF_NORMALIZED,
+            IndexColumns.DATA_ENTRIES,
             IndexColumns.DATA_KEYWORDS
     };
 
@@ -103,6 +106,7 @@
 
     private static final String NODE_NAME_PREFERENCE_SCREEN = "PreferenceScreen";
     private static final String NODE_NAME_CHECK_BOX_PREFERENCE = "CheckBoxPreference";
+    private static final String NODE_NAME_LIST_PREFERENCE = "ListPreference";
 
     private static Index sInstance;
     private final AtomicBoolean mIsAvailable = new AtomicBoolean(false);
@@ -348,22 +352,24 @@
                     final String title = cursor.getString(1);
                     final String summaryOn = cursor.getString(2);
                     final String summaryOff = cursor.getString(3);
-                    final String keywords = cursor.getString(4);
+                    final String entries = cursor.getString(4);
+                    final String keywords = cursor.getString(5);
 
-                    final String screenTitle = cursor.getString(5);
+                    final String screenTitle = cursor.getString(6);
 
-                    final String className = cursor.getString(6);
-                    final int iconResId = cursor.getInt(7);
+                    final String className = cursor.getString(7);
+                    final int iconResId = cursor.getInt(8);
 
-                    final String action = cursor.getString(8);
-                    final String targetPackage = cursor.getString(9);
-                    final String targetClass = cursor.getString(10);
+                    final String action = cursor.getString(9);
+                    final String targetPackage = cursor.getString(10);
+                    final String targetClass = cursor.getString(11);
 
                     SearchIndexableRaw data = new SearchIndexableRaw(packageContext);
                     data.rank = rank;
                     data.title = title;
                     data.summaryOn = summaryOn;
                     data.summaryOff = summaryOff;
+                    data.entries = entries;
                     data.keywords = keywords;
                     data.screenTitle = screenTitle;
                     data.className = className;
@@ -487,8 +493,8 @@
 
             // Insert rows for the main PreferenceScreen node. Rewrite the data for removing
             // hyphens.
-            updateOneRowWithFilteredData(database, localeStr, title, summary, null, fragmentName,
-                    screenTitle, iconResId, rank, keywords,
+            updateOneRowWithFilteredData(database, localeStr, title, summary, null, null,
+                    fragmentName, screenTitle, iconResId, rank, keywords,
                     intentAction, intentTargetPackage, intentTargetClass, true);
 
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -505,16 +511,21 @@
                 if (!nodeName.equals(NODE_NAME_CHECK_BOX_PREFERENCE)) {
                     summary = getDataSummary(context, attrs);
 
+                    String entries = null;
+                    if (nodeName.endsWith(NODE_NAME_LIST_PREFERENCE)) {
+                        entries = getDataEntries(context, attrs);
+                    }
+
                     // Insert rows for the child nodes of PreferenceScreen
-                    updateOneRowWithFilteredData(database, localeStr, title, summary, null,
+                    updateOneRowWithFilteredData(database, localeStr, title, summary, null, entries,
                             fragmentName, screenTitle, iconResId, rank, keywords,
                             intentAction, intentTargetPackage, intentTargetClass, true);
-                } else {
+                } else if (nodeName.equals(NODE_NAME_CHECK_BOX_PREFERENCE)) {
                     final String summaryOn = getDataSummaryOn(context, attrs);
                     final String summaryOff = getDataSummaryOff(context, attrs);
 
                     updateOneRowWithFilteredData(database, localeStr, title, summaryOn, summaryOff,
-                            fragmentName, screenTitle, iconResId, rank, keywords,
+                            null, fragmentName, screenTitle, iconResId, rank, keywords,
                             intentAction, intentTargetPackage, intentTargetClass, true);
                 }
             }
@@ -539,6 +550,7 @@
                 raw.title,
                 raw.summaryOn,
                 raw.summaryOff,
+                raw.entries,
                 raw.className,
                 raw.screenTitle,
                 raw.iconResId,
@@ -575,6 +587,7 @@
                                 raw.title,
                                 raw.summaryOn,
                                 raw.summaryOff,
+                                raw.entries,
                                 sir.className,
                                 raw.screenTitle,
                                 sir.iconResId,
@@ -617,8 +630,8 @@
     }
 
     private void updateOneRowWithFilteredData(SQLiteDatabase database, String locale,
-            String title, String summaryOn, String summaryOff, String className, String screenTitle,
-            int iconResId, int rank, String keywords,
+            String title, String summaryOn, String summaryOff, String entries, String className,
+            String screenTitle, int iconResId, int rank, String keywords,
             String intentAction, String intentTargetPackage, String intentTargetClass,
             boolean enabled) {
 
@@ -650,14 +663,14 @@
 
         updateOneRow(database, locale,
                 updatedTitle, normalizedTitle, updatedSummaryOn, normalizedSummaryOn,
-                updatedSummaryOff, normalizedSummaryOff, className, screenTitle, iconResId,
+                updatedSummaryOff, normalizedSummaryOff, entries, className, screenTitle, iconResId,
                 rank, keywords, intentAction, intentTargetPackage, intentTargetClass, enabled);
     }
 
     private void updateOneRow(SQLiteDatabase database, String locale,
             String updatedTitle, String normalizedTitle,
             String updatedSummaryOn, String normalizedSummaryOn,
-            String updatedSummaryOff, String normalizedSummaryOff, String className,
+            String updatedSummaryOff, String normalizedSummaryOff, String entries, String className,
             String screenTitle, int iconResId, int rank, String keywords,
             String intentAction, String intentTargetPackage, String intentTargetClass,
             boolean enabled) {
@@ -676,6 +689,7 @@
         values.put(IndexColumns.DATA_SUMMARY_ON_NORMALIZED, normalizedSummaryOn);
         values.put(IndexColumns.DATA_SUMMARY_OFF, updatedSummaryOff);
         values.put(IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, normalizedSummaryOff);
+        values.put(IndexColumns.DATA_ENTRIES, entries);
         values.put(IndexColumns.DATA_KEYWORDS, keywords);
         values.put(IndexColumns.CLASS_NAME, className);
         values.put(IndexColumns.SCREEN_TITLE, screenTitle);
@@ -712,6 +726,12 @@
                 com.android.internal.R.styleable.CheckBoxPreference_summaryOff);
     }
 
+    private String getDataEntries(Context context, AttributeSet attrs) {
+        return getDataEntries(context, attrs,
+                com.android.internal.R.styleable.ListPreference,
+                com.android.internal.R.styleable.ListPreference_entries);
+    }
+
     private String getDataKeywords(Context context, AttributeSet attrs) {
         return getData(context, attrs, R.styleable.Preference, R.styleable.Preference_keywords);
     }
@@ -731,6 +751,28 @@
         return (data != null) ? data.toString() : null;
     }
 
+    private String getDataEntries(Context context, AttributeSet set, int[] attrs, int resId) {
+        final TypedArray sa = context.obtainStyledAttributes(set, attrs);
+        final TypedValue tv = sa.peekValue(resId);
+
+        String[] data = null;
+        if (tv != null && tv.type == TypedValue.TYPE_REFERENCE) {
+            if (tv.resourceId != 0) {
+                data = context.getResources().getStringArray(tv.resourceId);
+            }
+        }
+        final int count = (data == null ) ? 0 : data.length;
+        if (count == 0) {
+            return null;
+        }
+        final StringBuilder result = new StringBuilder();
+        for (int n = 0; n < count; n++) {
+            result.append(data[n]);
+            result.append(" ");
+        }
+        return result.toString();
+    }
+
     private int getResId(Context context, AttributeSet set, int[] attrs, int resId) {
         final TypedArray sa = context.obtainStyledAttributes(set, attrs);
         final TypedValue tv = sa.peekValue(resId);
diff --git a/src/com/android/settings/search/IndexDatabaseHelper.java b/src/com/android/settings/search/IndexDatabaseHelper.java
index e16f6d5..65db6b4 100644
--- a/src/com/android/settings/search/IndexDatabaseHelper.java
+++ b/src/com/android/settings/search/IndexDatabaseHelper.java
@@ -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 = 104;
+    private static final int DATABASE_VERSION = 105;
 
     public interface Tables {
         public static final String TABLE_PREFS_INDEX = "prefs_index";
@@ -45,6 +45,7 @@
         public static final String DATA_SUMMARY_ON_NORMALIZED = "data_summary_on_normalized";
         public static final String DATA_SUMMARY_OFF = "data_summary_off";
         public static final String DATA_SUMMARY_OFF_NORMALIZED = "data_summary_off_normalized";
+        public static final String DATA_ENTRIES = "data_entries";
         public static final String DATA_KEYWORDS = "data_keywords";
         public static final String CLASS_NAME = "class_name";
         public static final String SCREEN_TITLE = "screen_title";
@@ -78,6 +79,8 @@
                     ", " +
                     IndexColumns.DATA_SUMMARY_OFF_NORMALIZED +
                     ", " +
+                    IndexColumns.DATA_ENTRIES +
+                    ", " +
                     IndexColumns.DATA_KEYWORDS +
                     ", " +
                     IndexColumns.SCREEN_TITLE +
diff --git a/src/com/android/settings/search/SearchIndexableRaw.java b/src/com/android/settings/search/SearchIndexableRaw.java
index e800535..c4d187e 100644
--- a/src/com/android/settings/search/SearchIndexableRaw.java
+++ b/src/com/android/settings/search/SearchIndexableRaw.java
@@ -31,6 +31,7 @@
     public String title;
     public String summaryOn;
     public String summaryOff;
+    public String entries;
     public String keywords;
 
     public String screenTitle;