DefaultSuggestionView.java revision 145693e12b77c193a65b7eaa038a272dd1f48f33
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.quicksearchbox.ui; 18 19import com.android.quicksearchbox.R; 20import com.android.quicksearchbox.Source; 21import com.android.quicksearchbox.SuggestionCursor; 22 23import android.content.Context; 24import android.content.res.ColorStateList; 25import android.graphics.drawable.Drawable; 26import android.text.Html; 27import android.text.Spannable; 28import android.text.SpannableString; 29import android.text.TextUtils; 30import android.text.style.TextAppearanceSpan; 31import android.util.AttributeSet; 32import android.util.Log; 33import android.view.View; 34import android.widget.ImageView; 35import android.widget.RelativeLayout; 36import android.widget.TextView; 37 38/** 39 * View for the items in the suggestions list. This includes promoted suggestions, 40 * sources, and suggestions under each source. 41 * 42 */ 43public class DefaultSuggestionView extends RelativeLayout implements SuggestionView { 44 45 private static final boolean DBG = false; 46 private static final String TAG = "QSB.SuggestionView"; 47 48 private TextView mText1; 49 private TextView mText2; 50 private ImageView mIcon1; 51 private ImageView mIcon2; 52 53 public DefaultSuggestionView(Context context, AttributeSet attrs, int defStyle) { 54 super(context, attrs, defStyle); 55 } 56 57 public DefaultSuggestionView(Context context, AttributeSet attrs) { 58 super(context, attrs); 59 } 60 61 public DefaultSuggestionView(Context context) { 62 super(context); 63 } 64 65 @Override 66 protected void onFinishInflate() { 67 super.onFinishInflate(); 68 mText1 = (TextView) findViewById(R.id.text1); 69 mText2 = (TextView) findViewById(R.id.text2); 70 mIcon1 = (ImageView) findViewById(R.id.icon1); 71 mIcon2 = (ImageView) findViewById(R.id.icon2); 72 } 73 74 public void bindAsSuggestion(SuggestionCursor suggestion) { 75 String format = suggestion.getSuggestionFormat(); 76 CharSequence text1 = formatText(suggestion.getSuggestionText1(), format); 77 CharSequence text2 = suggestion.getSuggestionText2Url(); 78 if (text2 != null) { 79 text2 = formatUrl(text2); 80 } else { 81 text2 = formatText(suggestion.getSuggestionText2(), format); 82 } 83 Drawable icon1 = getSuggestionDrawableIcon1(suggestion); 84 Drawable icon2 = getSuggestionDrawableIcon2(suggestion); 85 if (DBG) { 86 Log.d(TAG, "bindAsSuggestion(), text1=" + text1 + ",text2=" + text2 87 + ",icon1=" + icon1 + ",icon2=" + icon2); 88 } 89 // If there is no text for the second line, allow the first line to be up to two lines 90 int text1MaxLines = TextUtils.isEmpty(text2) ? 2 : 1; 91 mText1.setSingleLine(text1MaxLines == 1); 92 mText1.setMaxLines(text1MaxLines); 93 setText1(text1); 94 setText2(text2); 95 setIcon1(icon1); 96 setIcon2(icon2); 97 updateRefinable(suggestion); 98 } 99 100 protected void updateRefinable(SuggestionCursor suggestion) { 101 boolean refinable = mIcon2.getDrawable() == null 102 && !TextUtils.isEmpty(suggestion.getSuggestionQuery()); 103 setRefinable(suggestion, refinable); 104 } 105 106 protected void setRefinable(SuggestionCursor suggestion, boolean refinable) { 107 if (refinable) { 108 final int position = suggestion.getPosition(); 109 mIcon2.setOnClickListener(new View.OnClickListener() { 110 public void onClick(View v) { 111 Log.d(TAG, "Clicked query refine"); 112 SuggestionsView suggestions = (SuggestionsView) getParent(); 113 suggestions.onIcon2Clicked(position); 114 } 115 }); 116 Drawable icon2 = getContext().getResources().getDrawable(R.drawable.refine_query); 117 setIcon2(icon2); 118 } else { 119 mIcon2.setOnClickListener(null); 120 } 121 } 122 123 private CharSequence formatUrl(CharSequence url) { 124 SpannableString text = new SpannableString(url); 125 ColorStateList colors = getResources().getColorStateList(R.color.url_text); 126 text.setSpan(new TextAppearanceSpan(null, 0, 0, colors, null), 127 0, url.length(), 128 Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 129 return text; 130 } 131 132 public Drawable getSuggestionDrawableIcon1(SuggestionCursor suggestion) { 133 Source source = suggestion.getSuggestionSource(); 134 String icon1Id = suggestion.getSuggestionIcon1(); 135 Drawable icon1 = source.getIcon(icon1Id); 136 return icon1 == null ? source.getSourceIcon() : icon1; 137 } 138 139 public Drawable getSuggestionDrawableIcon2(SuggestionCursor suggestion) { 140 Source source = suggestion.getSuggestionSource(); 141 return source.getIcon(suggestion.getSuggestionIcon2()); 142 } 143 144 private CharSequence formatText(String str, String format) { 145 boolean isHtml = "html".equals(format); 146 if (isHtml && looksLikeHtml(str)) { 147 return Html.fromHtml(str); 148 } else { 149 return str; 150 } 151 } 152 153 private boolean looksLikeHtml(String str) { 154 if (TextUtils.isEmpty(str)) return false; 155 for (int i = str.length() - 1; i >= 0; i--) { 156 char c = str.charAt(i); 157 if (c == '>' || c == '&') return true; 158 } 159 return false; 160 } 161 162 /** 163 * Sets the first text line. 164 */ 165 private void setText1(CharSequence text) { 166 mText1.setText(text); 167 } 168 169 /** 170 * Sets the second text line. 171 */ 172 private void setText2(CharSequence text) { 173 mText2.setText(text); 174 if (TextUtils.isEmpty(text)) { 175 mText2.setVisibility(GONE); 176 } else { 177 mText2.setVisibility(VISIBLE); 178 } 179 } 180 181 /** 182 * Sets the left-hand-side icon. 183 */ 184 private void setIcon1(Drawable icon) { 185 setViewDrawable(mIcon1, icon); 186 } 187 188 /** 189 * Sets the right-hand-side icon. 190 */ 191 private void setIcon2(Drawable icon) { 192 setViewDrawable(mIcon2, icon); 193 } 194 195 /** 196 * Sets the drawable in an image view, makes sure the view is only visible if there 197 * is a drawable. 198 */ 199 private static void setViewDrawable(ImageView v, Drawable drawable) { 200 // Set the icon even if the drawable is null, since we need to clear any 201 // previous icon. 202 v.setImageDrawable(drawable); 203 204 if (drawable == null) { 205 v.setVisibility(View.GONE); 206 } else { 207 v.setVisibility(View.VISIBLE); 208 209 // This is a hack to get any animated drawables (like a 'working' spinner) 210 // to animate. You have to setVisible true on an AnimationDrawable to get 211 // it to start animating, but it must first have been false or else the 212 // call to setVisible will be ineffective. We need to clear up the story 213 // about animated drawables in the future, see http://b/1878430. 214 drawable.setVisible(false, false); 215 drawable.setVisible(true, false); 216 } 217 } 218 219} 220