am 313ea433: Make suggestion text color change based on the item state.

Merge commit '313ea433d18e7fd5438b94c0606c496fcc7a2f88'

* commit '313ea433d18e7fd5438b94c0606c496fcc7a2f88':
  Make suggestion text color change based on the item state.
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 49c94d1..c8e952f 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -18,7 +18,8 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.res.Resources.NotFoundException;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
 import android.database.Cursor;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
@@ -300,31 +301,19 @@
         ((SuggestionItemView)view).setColor(backgroundColor);
 
         final boolean isHtml = mFormatCol > 0 && "html".equals(cursor.getString(mFormatCol));
-        setViewText(cursor, views.mText1, mText1Col, isHtml);
-        setViewText(cursor, views.mText2, mText2Col, isHtml);
+        String text1 = null;
+        if (mText1Col >= 0) {
+            text1 = cursor.getString(mText1Col);
+        }
+        String text2 = null;
+        if (mText2Col >= 0) {
+            text2 = cursor.getString(mText2Col);
+        }
+        ((SuggestionItemView)view).setTextStrings(text1, text2, isHtml, mProviderContext);
         setViewIcon(cursor, views.mIcon1, mIconName1Col);
         setViewIcon(cursor, views.mIcon2, mIconName2Col);
     }
 
-    private void setViewText(Cursor cursor, TextView v, int textCol, boolean isHtml) {
-        if (v == null) {
-            return;
-        }
-        CharSequence text = null;
-        if (textCol >= 0) {
-            String str = cursor.getString(textCol);
-            text = (str != null && isHtml) ? Html.fromHtml(str) : str;
-        }
-        // Set the text even if it's null, since we need to clear any previous text.
-        v.setText(text);
-
-        if (TextUtils.isEmpty(text)) {
-            v.setVisibility(View.GONE);
-        } else {
-            v.setVisibility(View.VISIBLE);
-        }
-    }
-
     private void setViewIcon(Cursor cursor, ImageView v, int iconNameCol) {
         if (v == null) {
             return;
@@ -476,7 +465,7 @@
             if (drawable != null) {
                 mOutsideDrawablesCache.put(drawableId, drawable);
             }
-        } catch (NotFoundException nfe) {
+        } catch (Resources.NotFoundException nfe) {
             if (DBG) Log.d(LOG_TAG, "Icon resource not found: " + drawableId);
             // drawable = null;
         }
@@ -509,8 +498,82 @@
      * draws on top of the list view selection highlight).
      */
     private class SuggestionItemView extends ViewGroup {
+        /**
+         * Parses a given HTMl string and manages Spannable variants of the string for different
+         * states of the suggestion item (selected, pressed and normal). Colors for these different
+         * states are specified in the html font tag color attribute in the format '@<RESOURCEID>'
+         * where RESOURCEID is the ID of a ColorStateList or Color resource. 
+         */
+        private class MultiStateText {
+            private CharSequence mNormal = null;  // text to display in normal state.
+            private CharSequence mSelected = null;  // text to display in selected state.
+            private CharSequence mPressed = null;  // text to display in pressed state.
+            private String mPlainText = null;  // valid if the text is stateless plain text.
+
+            public MultiStateText(boolean isHtml, String text, Context context) {
+                if (!isHtml || text == null) {
+                    mPlainText = text;
+                    return;
+                }
+
+                String textNormal = text;
+                String textSelected = text;
+                String textPressed = text;
+                int textLength = text.length();
+                int start = text.indexOf("\"@");
+
+                // For each font color attribute which has the value in the form '@<RESOURCEID>',
+                // try to load the resource and create the display strings for the 3 states.
+                while (start >= 0) {
+                    start++;
+                    int end = text.indexOf("\"", start);
+                    if (end == -1) break;
+
+                    String colorIdString = text.substring(start, end);
+                    int colorId = Integer.parseInt(colorIdString.substring(1));
+                    try {
+                        // The following call works both for color lists and colors.
+                        ColorStateList csl = context.getResources().getColorStateList(colorId);
+                        int normalColor = csl.getColorForState(
+                                View.EMPTY_STATE_SET, csl.getDefaultColor());
+                        int selectedColor = csl.getColorForState(
+                                View.SELECTED_STATE_SET, csl.getDefaultColor());
+                        int pressedColor = csl.getColorForState(
+                                View.PRESSED_STATE_SET, csl.getDefaultColor());
+
+                        // Convert the int color values into a hex string, and strip the first 2
+                        // characters which will be the alpha (html doesn't want this).
+                        textNormal = textNormal.replace(colorIdString,
+                                "#" + Integer.toHexString(normalColor).substring(2));
+                        textSelected = textSelected.replace(colorIdString,
+                                "#" + Integer.toHexString(selectedColor).substring(2));
+                        textPressed = textPressed.replace(colorIdString,
+                                "#" + Integer.toHexString(pressedColor).substring(2));
+                    } catch (Resources.NotFoundException e) {
+                        // Nothing to do.
+                    }
+
+                    start = text.indexOf("\"@", end);
+                }
+                mNormal = Html.fromHtml(textNormal);
+                mSelected = Html.fromHtml(textSelected);
+                mPressed = Html.fromHtml(textPressed);
+            }
+            public CharSequence normal() {
+                return (mPlainText != null) ? mPlainText : mNormal;
+            }
+            public CharSequence selected() {
+                return (mPlainText != null) ? mPlainText : mSelected;
+            }
+            public CharSequence pressed() {
+                return (mPlainText != null) ? mPlainText : mPressed;
+            }
+        }
+
         private int mBackgroundColor;  // the background color to draw in normal state.
         private View mView;  // the suggestion item's view.
+        private MultiStateText mText1Strings = null;
+        private MultiStateText mText2Strings = null;
 
         protected SuggestionItemView(Context context, Cursor cursor) {
             // Initialize ourselves
@@ -537,12 +600,48 @@
             }
         }
 
+        private void setInitialTextForView(TextView view, MultiStateText multiState,
+                String plainText) {
+            // Set the text even if it's null, since we need to clear any previous text.
+            CharSequence text = (multiState != null) ? multiState.normal() : plainText;
+            view.setText(text);
+
+            if (TextUtils.isEmpty(text)) {
+                view.setVisibility(View.GONE);
+            } else {
+                view.setVisibility(View.VISIBLE);
+            }
+        }
+
+        public void setTextStrings(String text1, String text2, boolean isHtml, Context context) {
+            mText1Strings = new MultiStateText(isHtml, text1, context);
+            mText2Strings = new MultiStateText(isHtml, text2, context);
+
+            ChildViewCache views = (ChildViewCache) getTag();
+            setInitialTextForView(views.mText1, mText1Strings, text1);
+            setInitialTextForView(views.mText2, mText2Strings, text2);
+        }
+
+        public void updateTextViewContentIfRequired() {
+            // Check if the pressed or selected state has changed since the last call.
+            boolean isPressedNow = isPressed();
+            boolean isSelectedNow = isSelected();
+
+            ChildViewCache views = (ChildViewCache) getTag();
+            views.mText1.setText((isPressedNow ? mText1Strings.pressed() :
+                (isSelectedNow ? mText1Strings.selected() : mText1Strings.normal())));
+            views.mText2.setText((isPressedNow ? mText2Strings.pressed() :
+                (isSelectedNow ? mText2Strings.selected() : mText2Strings.normal())));
+        }
+
         public void setColor(int backgroundColor) {
             mBackgroundColor = backgroundColor;
         }
 
         @Override
         public void dispatchDraw(Canvas canvas) {
+            updateTextViewContentIfRequired();
+
             if (mBackgroundColor != 0 && !isPressed() && !isSelected()) {
                 canvas.drawColor(mBackgroundColor);
             }
diff --git a/core/res/res/color/search_url_text.xml b/core/res/res/color/search_url_text.xml
new file mode 100644
index 0000000..449fdf0
--- /dev/null
+++ b/core/res/res/color/search_url_text.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" android:color="@android:color/search_url_text_pressed"/>
+    <item android:state_selected="true" android:color="@android:color/search_url_text_selected"/>
+    <item android:color="@android:color/search_url_text_normal"/> <!-- not selected -->
+</selector>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index d284d0f..b7de997 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -74,7 +74,9 @@
     <color name="perms_normal_perm_color">#c0c0c0</color>
     
     <!-- For search-related UIs -->
-    <color name="search_url_text">#7fa87f</color>
+    <color name="search_url_text_normal">#7fa87f</color>
+    <color name="search_url_text_selected">@android:color/black</color>
+    <color name="search_url_text_pressed">@android:color/black</color>
     <color name="search_widget_corpus_item_background">@android:color/lighter_gray</color>
 
 </resources>