DefaultSuggestionView.java revision fb8ce18922dae59db424fce906b5c113797fe81e
11e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney/* 21e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * Copyright (C) 2009 The Android Open Source Project 31e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * 41e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * Licensed under the Apache License, Version 2.0 (the "License"); 51e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * you may not use this file except in compliance with the License. 61e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * You may obtain a copy of the License at 71e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * 81e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * http://www.apache.org/licenses/LICENSE-2.0 91e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * 101e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * Unless required by applicable law or agreed to in writing, software 111e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * distributed under the License is distributed on an "AS IS" BASIS, 121e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * See the License for the specific language governing permissions and 141e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * limitations under the License. 151e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney */ 161e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 171e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinneypackage com.android.quicksearchbox.ui; 181e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 192fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwoodimport com.android.quicksearchbox.QsbApplication; 201e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinneyimport com.android.quicksearchbox.R; 21fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport com.android.quicksearchbox.Source; 2293bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringertimport com.android.quicksearchbox.Suggestion; 232fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwoodimport com.android.quicksearchbox.SuggestionFormatter; 24e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwoodimport com.android.quicksearchbox.util.Consumer; 25e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwoodimport com.android.quicksearchbox.util.NowOrLater; 261e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 271e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinneyimport android.content.Context; 28965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringertimport android.content.res.ColorStateList; 291e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinneyimport android.graphics.drawable.Drawable; 30fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.text.Html; 31965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringertimport android.text.Spannable; 32965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringertimport android.text.SpannableString; 331e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinneyimport android.text.TextUtils; 34965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringertimport android.text.style.TextAppearanceSpan; 351e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinneyimport android.util.AttributeSet; 361e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinneyimport android.util.Log; 37fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringertimport android.view.ContextMenu; 3866ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwoodimport android.view.KeyEvent; 39fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringertimport android.view.MenuInflater; 40fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringertimport android.view.MenuItem; 411e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinneyimport android.view.View; 421e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinneyimport android.widget.ImageView; 431e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinneyimport android.widget.RelativeLayout; 441e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinneyimport android.widget.TextView; 451e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 461e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney/** 471e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * View for the items in the suggestions list. This includes promoted suggestions, 481e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * sources, and suggestions under each source. 491e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney */ 501e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinneypublic class DefaultSuggestionView extends RelativeLayout implements SuggestionView { 511e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 521e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney private static final boolean DBG = false; 531e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 545229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood public static final String VIEW_ID = "default"; 555229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood 56e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private static int sId = 0; 57e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood // give the TAG an unique ID to make debugging easier (there are lots of these!) 58e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private final String TAG = "QSB.SuggestionView:" + (sId++); 59e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 601e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney private TextView mText1; 611e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney private TextView mText2; 62e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private AsyncIcon mIcon1; 63e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private AsyncIcon mIcon2; 642fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood private final SuggestionFormatter mSuggestionFormatter; 65fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert private boolean mIsFromHistory; 6666ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood private boolean mRefineable; 6766ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood private int mPosition; 687010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert private SuggestionsAdapter mAdapter; 6966ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood private KeyListener mKeyListener; 701e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 711e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney public DefaultSuggestionView(Context context, AttributeSet attrs, int defStyle) { 721e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney super(context, attrs, defStyle); 732fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood mSuggestionFormatter = QsbApplication.get(context).getSuggestionFormatter(); 7466ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood } 751e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 761e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney public DefaultSuggestionView(Context context, AttributeSet attrs) { 771e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney super(context, attrs); 782fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood mSuggestionFormatter = QsbApplication.get(context).getSuggestionFormatter(); 791e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney } 801e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 811e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney public DefaultSuggestionView(Context context) { 821e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney super(context); 832fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood mSuggestionFormatter = QsbApplication.get(context).getSuggestionFormatter(); 841e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney } 851e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 861e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney @Override 871e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney protected void onFinishInflate() { 881e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney super.onFinishInflate(); 891e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney mText1 = (TextView) findViewById(R.id.text1); 901e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney mText2 = (TextView) findViewById(R.id.text2); 91e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mIcon1 = new AsyncIcon((ImageView) findViewById(R.id.icon1)){ 92e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood // override default icon (when no other available) with default source icon 93e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood @Override 94e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood protected String getFallbackIconId(Source source) { 95e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return source.getSourceIconUri().toString(); 96e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 97e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood @Override 98e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood protected Drawable getFallbackIcon(Source source) { 99e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return source.getSourceIcon(); 100e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 101e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood }; 102e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mIcon2 = new AsyncIcon((ImageView) findViewById(R.id.icon2)); 10366ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood // for some reason, creating mKeyListener inside the constructor causes it not to work. 10466ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood mKeyListener = new KeyListener(); 10566ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood 10666ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood setOnKeyListener(mKeyListener); 1071e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney } 1081e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 1095229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood public void bindAsSuggestion(Suggestion suggestion, String userQuery) { 11066ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood setOnClickListener(new ClickListener()); 11166ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood 1125229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood CharSequence text1 = formatText(suggestion.getSuggestionText1(), suggestion, userQuery); 113965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringert CharSequence text2 = suggestion.getSuggestionText2Url(); 114965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringert if (text2 != null) { 115965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringert text2 = formatUrl(text2); 116965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringert } else { 1175229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood text2 = formatText(suggestion.getSuggestionText2(), suggestion, null); 118965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringert } 119145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert // If there is no text for the second line, allow the first line to be up to two lines 120bf18086dbcdc3cbc50409940b58fbc3a7dcf3a88Bjorn Bringert if (TextUtils.isEmpty(text2)) { 121bf18086dbcdc3cbc50409940b58fbc3a7dcf3a88Bjorn Bringert mText1.setSingleLine(false); 122bf18086dbcdc3cbc50409940b58fbc3a7dcf3a88Bjorn Bringert mText1.setMaxLines(2); 123bf18086dbcdc3cbc50409940b58fbc3a7dcf3a88Bjorn Bringert mText1.setEllipsize(TextUtils.TruncateAt.START); 124bf18086dbcdc3cbc50409940b58fbc3a7dcf3a88Bjorn Bringert } else { 125bf18086dbcdc3cbc50409940b58fbc3a7dcf3a88Bjorn Bringert mText1.setSingleLine(true); 126bf18086dbcdc3cbc50409940b58fbc3a7dcf3a88Bjorn Bringert mText1.setMaxLines(1); 127bf18086dbcdc3cbc50409940b58fbc3a7dcf3a88Bjorn Bringert mText1.setEllipsize(TextUtils.TruncateAt.MIDDLE); 128bf18086dbcdc3cbc50409940b58fbc3a7dcf3a88Bjorn Bringert } 1291e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney setText1(text1); 1301e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney setText2(text2); 131e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mIcon1.set(suggestion.getSuggestionSource(), suggestion.getSuggestionIcon1()); 132e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mIcon2.set(suggestion.getSuggestionSource(), suggestion.getSuggestionIcon2()); 133fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert updateIsFromHistory(suggestion); 134145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert updateRefinable(suggestion); 135fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert 136fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert setLongClickable(needsContextMenu()); 137fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert 138fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert if (DBG) { 139fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert Log.d(TAG, "bindAsSuggestion(), text1=" + text1 + ",text2=" + text2 + ",q='" + 140fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert userQuery + "',refinable=" + mRefineable + ",fromHistory=" + mIsFromHistory); 141fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert } 142145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert } 143145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert 1445229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood public void bindAdapter(SuggestionsAdapter adapter, int position) { 1455229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood mAdapter = adapter; 1465229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood mPosition = position; 1475229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood } 1485229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood 149fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert protected boolean needsContextMenu() { 150fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert return isFromHistory(); 151fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert } 152fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert 153fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert protected boolean isFromHistory() { 154fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert return mIsFromHistory; 155fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert } 156fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert 157fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert protected void updateIsFromHistory(Suggestion suggestion) { 158fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert mIsFromHistory = suggestion.isSuggestionShortcut() || suggestion.isHistorySuggestion(); 159fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert } 160fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert 1615229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood protected void updateRefinable(Suggestion suggestion) { 16266ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood mRefineable = 163014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert suggestion.isWebSearchSuggestion() 164e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood && mIcon2.getView().getDrawable() == null 165145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert && !TextUtils.isEmpty(suggestion.getSuggestionQuery()); 1665c383769c9cf23ebb38e03f1245007b8f7e48950Mathew Inwood if (DBG) Log.d(TAG, "updateRefinable: " + mRefineable); 16766ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood setRefinable(suggestion, mRefineable); 168145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert } 169145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert 1705229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood protected void setRefinable(Suggestion suggestion, boolean refinable) { 171145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert if (refinable) { 172e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mIcon2.getView().setOnClickListener(new View.OnClickListener() { 173145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert public void onClick(View v) { 1747010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert onSuggestionQueryRefineClicked(); 175145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert } 176145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert }); 177e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mIcon2.getView().setFocusable(true); 178e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mIcon2.getView().setOnKeyListener(mKeyListener); 1796b8dba4c144efb18faa9720d022db2aa7a532f59Bjorn Bringert Drawable icon2 = getContext().getResources().getDrawable(R.drawable.edit_query); 1806b8dba4c144efb18faa9720d022db2aa7a532f59Bjorn Bringert Drawable background = 1816b8dba4c144efb18faa9720d022db2aa7a532f59Bjorn Bringert getContext().getResources().getDrawable(R.drawable.edit_query_background); 182e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mIcon2.setDrawable(icon2, background, String.valueOf(R.drawable.edit_query)); 183145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert } else { 184e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mIcon2.getView().setOnClickListener(null); 185e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mIcon2.getView().setFocusable(false); 186e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mIcon2.getView().setOnKeyListener(null); 187145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert } 1881e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney } 1891e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 190965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringert private CharSequence formatUrl(CharSequence url) { 191965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringert SpannableString text = new SpannableString(url); 192965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringert ColorStateList colors = getResources().getColorStateList(R.color.url_text); 193965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringert text.setSpan(new TextAppearanceSpan(null, 0, 0, colors, null), 194965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringert 0, url.length(), 195965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringert Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 196965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringert return text; 197965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringert } 198965d98377ddfdc52b772c2444d840000b665e000Bjorn Bringert 1995229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood private CharSequence formatText(String str, Suggestion suggestion, 2005229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood String userQuery) { 2012fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood boolean isHtml = "html".equals(suggestion.getSuggestionFormat()); 202fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (isHtml && looksLikeHtml(str)) { 203fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return Html.fromHtml(str); 2045229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood } else if (suggestion.isWebSearchSuggestion() && !TextUtils.isEmpty(userQuery)) { 2055229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood return mSuggestionFormatter.formatSuggestion(userQuery, str); 206fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } else { 207fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return str; 208fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 209fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 210fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 211fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private boolean looksLikeHtml(String str) { 212fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (TextUtils.isEmpty(str)) return false; 213fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert for (int i = str.length() - 1; i >= 0; i--) { 214fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert char c = str.charAt(i); 215fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (c == '>' || c == '&') return true; 216fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 217fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return false; 218fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 219fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 220dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert /** 221dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert * Sets the first text line. 222dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert */ 223dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert private void setText1(CharSequence text) { 2241e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney mText1.setText(text); 2251e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney } 2261e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 227dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert /** 228dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert * Sets the second text line. 229dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert */ 230dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert private void setText2(CharSequence text) { 2311e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney mText2.setText(text); 2321e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney if (TextUtils.isEmpty(text)) { 2331e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney mText2.setVisibility(GONE); 2341e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney } else { 2351e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney mText2.setVisibility(VISIBLE); 2361e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney } 2371e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney } 2381e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 239dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert /** 2401e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * Sets the drawable in an image view, makes sure the view is only visible if there 2411e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney * is a drawable. 2421e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney */ 2431e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney private static void setViewDrawable(ImageView v, Drawable drawable) { 2441e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney // Set the icon even if the drawable is null, since we need to clear any 2451e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney // previous icon. 2461e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney v.setImageDrawable(drawable); 2471e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 2481e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney if (drawable == null) { 2491e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney v.setVisibility(View.GONE); 2501e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney } else { 2511e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney v.setVisibility(View.VISIBLE); 2521e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 2531e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney // This is a hack to get any animated drawables (like a 'working' spinner) 2541e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney // to animate. You have to setVisible true on an AnimationDrawable to get 2551e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney // it to start animating, but it must first have been false or else the 2561e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney // call to setVisible will be ineffective. We need to clear up the story 2571e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney // about animated drawables in the future, see http://b/1878430. 2581e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney drawable.setVisible(false, false); 2591e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney drawable.setVisible(true, false); 2601e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney } 2611e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney } 2621e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney 263fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert @Override 264fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert protected void onCreateContextMenu(ContextMenu menu) { 265fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert super.onCreateContextMenu(menu); 266fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert if (isFromHistory()) { 267fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert MenuInflater inflater = new MenuInflater(getContext()); 268fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert inflater.inflate(R.menu.remove_from_history, menu); 269fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert MenuItem removeFromHistory = menu.findItem(R.id.remove_from_history); 270fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert removeFromHistory.setOnMenuItemClickListener(new RemoveFromHistoryListener()); 271fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert } 272fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert } 273fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert 2747010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert protected void onSuggestionClicked() { 2757010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert if (mAdapter != null) { 2767010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert mAdapter.onSuggestionClicked(mPosition); 2777010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert } 2787010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert } 2797010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert 2807010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert protected void onSuggestionQuickContactClicked() { 2817010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert if (mAdapter != null) { 2827010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert mAdapter.onSuggestionQuickContactClicked(mPosition); 2837010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert } 2847010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert } 2857010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert 286fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert protected void onRemoveFromHistoryClicked() { 2877010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert if (mAdapter != null) { 288fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert mAdapter.onSuggestionRemoveFromHistoryClicked(mPosition); 2897010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert } 2907010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert } 2917010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert 2927010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert protected void onSuggestionQueryRefineClicked() { 2937010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert if (mAdapter != null) { 2947010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert mAdapter.onSuggestionQueryRefineClicked(mPosition); 295c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert } 296c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert } 297c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert 29866ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood private class ClickListener implements OnClickListener { 29966ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood public void onClick(View v) { 3007010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert onSuggestionClicked(); 30166ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood } 30266ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood } 30366ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood 304fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert private class RemoveFromHistoryListener implements MenuItem.OnMenuItemClickListener { 305fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert public boolean onMenuItemClick(MenuItem item) { 306fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert onRemoveFromHistoryClicked(); 307fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert return false; 30866ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood } 30966ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood } 31066ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood 31166ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood private class KeyListener implements View.OnKeyListener { 31266ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood public boolean onKey(View v, int keyCode, KeyEvent event) { 31366ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood boolean consumed = false; 31466ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood if (event.getAction() == KeyEvent.ACTION_DOWN) { 315e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && v != mIcon2.getView()) { 316e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood consumed = mIcon2.getView().requestFocus(); 31766ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood if (DBG) Log.d(TAG, "onKey Icon2 accepted focus: " + consumed); 318e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && v == mIcon2.getView()) { 31966ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood consumed = requestFocus(); 32066ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood if (DBG) Log.d(TAG, "onKey SuggestionView accepted focus: " + consumed); 32166ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood } 32266ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood } 32366ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood return consumed; 32466ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood } 32566ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood } 32666ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood 327e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private class AsyncIcon { 328e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private final ImageView mView; 329e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private String mCurrentId; 330e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private String mWantedId; 331e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 332e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood public AsyncIcon(ImageView view) { 333e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mView = view; 334e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 335e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 336e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood public void set(final Source source, final String iconId) { 337e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (iconId != null) { 338e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mWantedId = iconId; 339e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (!TextUtils.equals(mWantedId, mCurrentId)) { 340e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (DBG) Log.d(TAG, "getting icon Id=" + iconId); 341e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood NowOrLater<Drawable> icon = source.getIcon(iconId); 342e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (icon.haveNow()) { 343e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (DBG) Log.d(TAG, "getIcon ready now"); 344e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood handleNewDrawable(icon.getNow(), iconId, source); 345e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } else { 346e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood // make sure old icon is not visible while new one is loaded 347e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (DBG) Log.d(TAG , "getIcon getting later"); 348e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood clearDrawable(); 349e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood icon.getLater(new Consumer<Drawable>(){ 350e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood public boolean consume(Drawable icon) { 351e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (DBG) { 352e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood Log.d(TAG, "IconConsumer.consume got id " + iconId + 353e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood " want id " + mWantedId); 354e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 355e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood // ensure we have not been re-bound since the request was made. 356e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (TextUtils.equals(iconId, mWantedId)) { 357e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood handleNewDrawable(icon, iconId, source); 358e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return true; 359e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 360e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return false; 361e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood }}); 362e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 363e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 364e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } else { 365e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mWantedId = null; 366e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood handleNewDrawable(null, null, source); 367e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 368e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 369e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 370e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood public ImageView getView() { 371e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return mView; 372e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 373e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 374e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private void handleNewDrawable(Drawable icon, String id, Source source) { 375e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (icon == null) { 376e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mWantedId = getFallbackIconId(source); 377e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (TextUtils.equals(mWantedId, mCurrentId)) { 378e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return; 379e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 380e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood icon = getFallbackIcon(source); 381e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 382e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood setDrawable(icon, id); 383e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 384e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 385e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood public void setDrawable(Drawable icon, Drawable background, String id) { 386e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mCurrentId = id; 3875c383769c9cf23ebb38e03f1245007b8f7e48950Mathew Inwood mWantedId = id; 3885c383769c9cf23ebb38e03f1245007b8f7e48950Mathew Inwood setViewDrawable(mView, icon); 389e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mView.setBackgroundDrawable(background); 390e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 391e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 392e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private void setDrawable(Drawable icon, String id) { 393e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mCurrentId = id; 394e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood setViewDrawable(mView, icon); 395e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 396e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 397e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private void clearDrawable() { 398e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mCurrentId = null; 399e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mView.setImageDrawable(null); 400e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 401e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 402e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood protected String getFallbackIconId(Source source) { 403e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return null; 404e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 405e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 406e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood protected Drawable getFallbackIcon(Source source) { 407e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return null; 408e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 409e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 410e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 4111e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney} 412