1c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert/*
2c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert * Copyright (C) 2010 The Android Open Source Project
3c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert *
4c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
5c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert * you may not use this file except in compliance with the License.
6c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert * You may obtain a copy of the License at
7c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert *
8c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert *      http://www.apache.org/licenses/LICENSE-2.0
9c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert *
10c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
11c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
12c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert * See the License for the specific language governing permissions and
14c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert * limitations under the License.
15c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert */
16c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert
17c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringertpackage com.android.quicksearchbox.ui;
18c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert
197010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport com.android.quicksearchbox.Corpora;
207010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport com.android.quicksearchbox.Corpus;
217010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport com.android.quicksearchbox.CorpusResult;
227010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport com.android.quicksearchbox.Logger;
238b2936607176720172aee068abc5631bdf77e843Bjorn Bringertimport com.android.quicksearchbox.Promoter;
247010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport com.android.quicksearchbox.QsbApplication;
257010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport com.android.quicksearchbox.R;
260a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwoodimport com.android.quicksearchbox.SearchActivity;
277010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport com.android.quicksearchbox.SuggestionCursor;
287010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport com.android.quicksearchbox.Suggestions;
297010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport com.android.quicksearchbox.VoiceSearch;
307010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
31c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringertimport android.content.Context;
327010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport android.database.DataSetObserver;
337010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport android.graphics.drawable.Drawable;
347010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport android.text.Editable;
359e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwoodimport android.text.TextUtils;
367010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport android.text.TextWatcher;
37c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringertimport android.util.AttributeSet;
387010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport android.util.Log;
39c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringertimport android.view.KeyEvent;
407010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport android.view.View;
417010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport android.view.inputmethod.CompletionInfo;
42c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringertimport android.view.inputmethod.InputMethodManager;
437010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport android.widget.AbsListView;
447010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport android.widget.ImageButton;
45fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwoodimport android.widget.ListAdapter;
4611234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringertimport android.widget.RelativeLayout;
47748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwoodimport android.widget.TextView;
48748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwoodimport android.widget.TextView.OnEditorActionListener;
49c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert
507010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport java.util.ArrayList;
517010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport java.util.Arrays;
527010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
5377909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringertpublic abstract class SearchActivityView extends RelativeLayout {
540a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    protected static final boolean DBG = false;
550a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    protected static final String TAG = "QSB.SearchActivityView";
567010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
577010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    // The string used for privateImeOptions to identify to the IME that it should not show
587010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    // a microphone button since one already exists in the search dialog.
597010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    // TODO: This should move to android-common or something.
607010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private static final String IME_OPTION_NO_MICROPHONE = "nm";
617010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
628b2936607176720172aee068abc5631bdf77e843Bjorn Bringert    private Corpus mCorpus;
638b2936607176720172aee068abc5631bdf77e843Bjorn Bringert
640a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    protected QueryTextView mQueryTextView;
657010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    // True if the query was empty on the previous call to updateQuery()
660a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    protected boolean mQueryWasEmpty = true;
670a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    protected Drawable mQueryTextEmptyBg;
680a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    protected Drawable mQueryTextNotEmptyBg;
690a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood
70fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    protected SuggestionsListView<ListAdapter> mSuggestionsView;
71fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    protected SuggestionsAdapter<ListAdapter> mSuggestionsAdapter;
727010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
732cbf1d099dbd04c612e3cba34a70293705730fa0Amith Yamasani    protected ImageButton mSearchCloseButton;
740a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    protected ImageButton mSearchGoButton;
750a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    protected ImageButton mVoiceSearchButton;
767010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
770a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    protected ButtonsKeyListener mButtonsKeyListener;
787010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
797010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private boolean mUpdateSuggestions;
807010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
817010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private QueryListener mQueryListener;
827010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private SearchClickListener mSearchClickListener;
83b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert    protected View.OnClickListener mExitClickListener;
847010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
8511234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert    public SearchActivityView(Context context) {
86c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert        super(context);
87c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert    }
88c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert
8911234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert    public SearchActivityView(Context context, AttributeSet attrs) {
90c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert        super(context, attrs);
91c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert    }
92c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert
9311234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert    public SearchActivityView(Context context, AttributeSet attrs, int defStyle) {
94c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert        super(context, attrs, defStyle);
95c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert    }
96c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert
977010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    @Override
987010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    protected void onFinishInflate() {
997010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mQueryTextView = (QueryTextView) findViewById(R.id.search_src_text);
1007010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
1017010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSuggestionsView = (SuggestionsView) findViewById(R.id.suggestions);
1027010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSuggestionsView.setOnScrollListener(new InputMethodCloser());
1037010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSuggestionsView.setOnKeyListener(new SuggestionsViewKeyListener());
1047010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSuggestionsView.setOnFocusChangeListener(new SuggestListFocusListener());
1057010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
1067010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSuggestionsAdapter = createSuggestionsAdapter();
1077010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        // TODO: why do we need focus listeners both on the SuggestionsView and the individual
1087010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        // suggestions?
1097010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSuggestionsAdapter.setOnFocusChangeListener(new SuggestListFocusListener());
1107010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
1112cbf1d099dbd04c612e3cba34a70293705730fa0Amith Yamasani        mSearchCloseButton = (ImageButton) findViewById(R.id.search_close_btn);
1127010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchGoButton = (ImageButton) findViewById(R.id.search_go_btn);
1137010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mVoiceSearchButton = (ImageButton) findViewById(R.id.search_voice_btn);
1147a427f9830f7f9201299fae34a93016c77b0a569Mathew Inwood        mVoiceSearchButton.setImageDrawable(getVoiceSearchIcon());
1157010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
1167010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mQueryTextView.addTextChangedListener(new SearchTextWatcher());
117748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwood        mQueryTextView.setOnEditorActionListener(new QueryTextEditorActionListener());
1187010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mQueryTextView.setOnFocusChangeListener(new QueryTextViewFocusListener());
1197010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mQueryTextEmptyBg = mQueryTextView.getBackground();
1207010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
1217010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchGoButton.setOnClickListener(new SearchGoButtonClickListener());
1227010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
1230a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        mButtonsKeyListener = new ButtonsKeyListener();
1240a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        mSearchGoButton.setOnKeyListener(mButtonsKeyListener);
1250a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        mVoiceSearchButton.setOnKeyListener(mButtonsKeyListener);
1262cbf1d099dbd04c612e3cba34a70293705730fa0Amith Yamasani        if (mSearchCloseButton != null) {
1272cbf1d099dbd04c612e3cba34a70293705730fa0Amith Yamasani            mSearchCloseButton.setOnKeyListener(mButtonsKeyListener);
1282cbf1d099dbd04c612e3cba34a70293705730fa0Amith Yamasani            mSearchCloseButton.setOnClickListener(new CloseClickListener());
1292cbf1d099dbd04c612e3cba34a70293705730fa0Amith Yamasani        }
1307010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
1317010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mUpdateSuggestions = true;
1327010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
1337010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
1340a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    public abstract void onResume();
1350a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood
1360a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    public abstract void onStop();
1370a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood
1382e684983c6a20faa209e42f6c63337cfcb34fc71Amith Yamasani    public void onPause() {
1392e684983c6a20faa209e42f6c63337cfcb34fc71Amith Yamasani        // Override if necessary
1402e684983c6a20faa209e42f6c63337cfcb34fc71Amith Yamasani    }
1412e684983c6a20faa209e42f6c63337cfcb34fc71Amith Yamasani
1427010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public void start() {
143fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        mSuggestionsAdapter.getListAdapter().registerDataSetObserver(new SuggestionsObserver());
144fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        mSuggestionsView.setSuggestionsAdapter(mSuggestionsAdapter);
1457010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
1467010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
1477010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public void destroy() {
148fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        mSuggestionsView.setSuggestionsAdapter(null);  // closes mSuggestionsAdapter
1497010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
1505880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert
1517010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    // TODO: Get rid of this. To make it more easily testable,
1527010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    // the SearchActivityView should not depend on QsbApplication.
1537010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    protected QsbApplication getQsbApplication() {
1547010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return QsbApplication.get(getContext());
1557010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
1567010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
1577a427f9830f7f9201299fae34a93016c77b0a569Mathew Inwood    protected Drawable getVoiceSearchIcon() {
1587a427f9830f7f9201299fae34a93016c77b0a569Mathew Inwood        return getResources().getDrawable(R.drawable.ic_btn_speak_now);
1597a427f9830f7f9201299fae34a93016c77b0a569Mathew Inwood    }
1607a427f9830f7f9201299fae34a93016c77b0a569Mathew Inwood
1617a427f9830f7f9201299fae34a93016c77b0a569Mathew Inwood    protected VoiceSearch getVoiceSearch() {
1627010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return getQsbApplication().getVoiceSearch();
1637010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
1647010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
165fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    protected SuggestionsAdapter<ListAdapter> createSuggestionsAdapter() {
166fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        return new DelayingSuggestionsAdapter<ListAdapter>(new SuggestionsListAdapter(
16777909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert                getQsbApplication().getSuggestionViewFactory()));
1687010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
1697010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
1700a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    protected Corpora getCorpora() {
1717010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return getQsbApplication().getCorpora();
1727010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
1737010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
1748b2936607176720172aee068abc5631bdf77e843Bjorn Bringert    public Corpus getCorpus() {
1758b2936607176720172aee068abc5631bdf77e843Bjorn Bringert        return mCorpus;
1768b2936607176720172aee068abc5631bdf77e843Bjorn Bringert    }
1777010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
1788b2936607176720172aee068abc5631bdf77e843Bjorn Bringert    protected abstract Promoter createSuggestionsPromoter();
1797010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
1800a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    protected Corpus getCorpus(String sourceName) {
1810a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        if (sourceName == null) return null;
1820a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        Corpus corpus = getCorpora().getCorpus(sourceName);
1837010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        if (corpus == null) {
1840a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood            Log.w(TAG, "Unknown corpus " + sourceName);
1850a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood            return null;
1867010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
1870a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        return corpus;
1887010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
1897010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
1908b2936607176720172aee068abc5631bdf77e843Bjorn Bringert    public void onCorpusSelected(String corpusName) {
1918b2936607176720172aee068abc5631bdf77e843Bjorn Bringert        setCorpus(corpusName);
1928b2936607176720172aee068abc5631bdf77e843Bjorn Bringert        focusQueryTextView();
1938b2936607176720172aee068abc5631bdf77e843Bjorn Bringert        showInputMethodForQuery();
1948b2936607176720172aee068abc5631bdf77e843Bjorn Bringert    }
1958b2936607176720172aee068abc5631bdf77e843Bjorn Bringert
1960a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    public void setCorpus(String corpusName) {
1970a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        if (DBG) Log.d(TAG, "setCorpus(" + corpusName + ")");
1980a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        Corpus corpus = getCorpus(corpusName);
1990a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        setCorpus(corpus);
2008b2936607176720172aee068abc5631bdf77e843Bjorn Bringert        updateUi();
2018b2936607176720172aee068abc5631bdf77e843Bjorn Bringert    }
2028b2936607176720172aee068abc5631bdf77e843Bjorn Bringert
2038b2936607176720172aee068abc5631bdf77e843Bjorn Bringert    protected void setCorpus(Corpus corpus) {
2048b2936607176720172aee068abc5631bdf77e843Bjorn Bringert        mCorpus = corpus;
2058b2936607176720172aee068abc5631bdf77e843Bjorn Bringert        mSuggestionsAdapter.setPromoter(createSuggestionsPromoter());
206dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert        Suggestions suggestions = getSuggestions();
207dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert        if (corpus == null || suggestions == null || !suggestions.expectsCorpus(corpus)) {
208dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert            getActivity().updateSuggestions();
209dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert        }
2107010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
2117010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
2120a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    public String getCorpusName() {
2138b2936607176720172aee068abc5631bdf77e843Bjorn Bringert        Corpus corpus = getCorpus();
2148b2936607176720172aee068abc5631bdf77e843Bjorn Bringert        return corpus == null ? null : corpus.getName();
2150a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    }
2160a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood
2170a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    public abstract Corpus getSearchCorpus();
2180a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood
2197010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public Corpus getWebCorpus() {
2207010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        Corpus webCorpus = getCorpora().getWebCorpus();
2217010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        if (webCorpus == null) {
2227010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            Log.e(TAG, "No web corpus");
2237010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
2247010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return webCorpus;
2257010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
2267010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
227f5a8912d5da80378d38b667eba4aaa0555aea7bdMathew Inwood    public void setMaxPromotedSuggestions(int maxPromoted) {
228fdb80c2962c88ac62dcd7ee7f2fab1857b61506bMathew Inwood        mSuggestionsView.setLimitSuggestionsToViewHeight(false);
2297010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSuggestionsAdapter.setMaxPromoted(maxPromoted);
2307010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
2317010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
232fdb80c2962c88ac62dcd7ee7f2fab1857b61506bMathew Inwood    public void limitSuggestionsToViewHeight() {
233fdb80c2962c88ac62dcd7ee7f2fab1857b61506bMathew Inwood        mSuggestionsView.setLimitSuggestionsToViewHeight(true);
234fdb80c2962c88ac62dcd7ee7f2fab1857b61506bMathew Inwood    }
235fdb80c2962c88ac62dcd7ee7f2fab1857b61506bMathew Inwood
236f5a8912d5da80378d38b667eba4aaa0555aea7bdMathew Inwood    public void setMaxPromotedResults(int maxPromoted) {
237f5a8912d5da80378d38b667eba4aaa0555aea7bdMathew Inwood    }
238f5a8912d5da80378d38b667eba4aaa0555aea7bdMathew Inwood
239f5a8912d5da80378d38b667eba4aaa0555aea7bdMathew Inwood    public void limitResultsToViewHeight() {
240f5a8912d5da80378d38b667eba4aaa0555aea7bdMathew Inwood    }
241f5a8912d5da80378d38b667eba4aaa0555aea7bdMathew Inwood
2427010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public void setQueryListener(QueryListener listener) {
2437010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mQueryListener = listener;
2447010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
2457010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
2467010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public void setSearchClickListener(SearchClickListener listener) {
2477010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchClickListener = listener;
2487010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
2497010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
2500a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    public abstract void showCorpusSelectionDialog();
2517010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
2527010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public void setVoiceSearchButtonClickListener(View.OnClickListener listener) {
2537010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        if (mVoiceSearchButton != null) {
2547010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            mVoiceSearchButton.setOnClickListener(listener);
2557010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
2567010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
2577010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
2587010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public void setSuggestionClickListener(final SuggestionClickListener listener) {
2597010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSuggestionsAdapter.setSuggestionClickListener(listener);
2607010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mQueryTextView.setCommitCompletionListener(new QueryTextView.CommitCompletionListener() {
2617010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            @Override
2627010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            public void onCommitCompletion(int position) {
2637010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                mSuggestionsAdapter.onSuggestionClicked(position);
2647010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            }
2657010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        });
2667010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
2677010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
2689e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood    public void setExitClickListener(final View.OnClickListener listener) {
2699e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood        mExitClickListener = listener;
2709e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood    }
2719e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood
2727010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public Suggestions getSuggestions() {
2737010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return mSuggestionsAdapter.getSuggestions();
2747010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
2757010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
276fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    public SuggestionCursor getCurrentPromotedSuggestions() {
277fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood        return mSuggestionsAdapter.getCurrentPromotedSuggestions();
2787010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
2797010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
2807010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public void setSuggestions(Suggestions suggestions) {
2817010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        suggestions.acquire();
2827010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSuggestionsAdapter.setSuggestions(suggestions);
2837010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
2847010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
2857010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public void clearSuggestions() {
2867010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSuggestionsAdapter.setSuggestions(null);
2877010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
2887010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
2897010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public String getQuery() {
2907010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        CharSequence q = mQueryTextView.getText();
2917010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return q == null ? "" : q.toString();
2927010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
2937010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
294b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert    public boolean isQueryEmpty() {
295b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert        return TextUtils.isEmpty(getQuery());
296b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert    }
297b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert
2987010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    /**
2997010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     * Sets the text in the query box. Does not update the suggestions.
3007010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     */
3017010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public void setQuery(String query, boolean selectAll) {
3027010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mUpdateSuggestions = false;
3037010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mQueryTextView.setText(query);
3047010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mQueryTextView.setTextSelection(selectAll);
3057010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mUpdateSuggestions = true;
3067010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
3077010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
3080a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    protected SearchActivity getActivity() {
309c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert        Context context = getContext();
3100a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        if (context instanceof SearchActivity) {
3110a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood            return (SearchActivity) context;
312c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert        } else {
313c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert            return null;
314c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert        }
315c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert    }
316c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert
3178749e424d7645e708f238530621248abb567e3beBjorn Bringert    public void hideSuggestions() {
3188749e424d7645e708f238530621248abb567e3beBjorn Bringert        mSuggestionsView.setVisibility(GONE);
3198749e424d7645e708f238530621248abb567e3beBjorn Bringert    }
3208749e424d7645e708f238530621248abb567e3beBjorn Bringert
3218749e424d7645e708f238530621248abb567e3beBjorn Bringert    public void showSuggestions() {
3228749e424d7645e708f238530621248abb567e3beBjorn Bringert        mSuggestionsView.setVisibility(VISIBLE);
3238749e424d7645e708f238530621248abb567e3beBjorn Bringert    }
3248749e424d7645e708f238530621248abb567e3beBjorn Bringert
3257010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public void focusQueryTextView() {
3267010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mQueryTextView.requestFocus();
3277010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
3287010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
3298b2936607176720172aee068abc5631bdf77e843Bjorn Bringert    protected void updateUi() {
330b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert        updateUi(isQueryEmpty());
3318b2936607176720172aee068abc5631bdf77e843Bjorn Bringert    }
3328b2936607176720172aee068abc5631bdf77e843Bjorn Bringert
3337010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    protected void updateUi(boolean queryEmpty) {
3347010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        updateQueryTextView(queryEmpty);
3357010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        updateSearchGoButton(queryEmpty);
3367010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        updateVoiceSearchButton(queryEmpty);
3377010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
3387010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
33955938341e72f1581d6caae51a31d8d72a1cd8138Amith Yamasani    protected void updateQueryTextView(boolean queryEmpty) {
3407010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        if (queryEmpty) {
3417010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            if (isSearchCorpusWeb()) {
3427010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                mQueryTextView.setBackgroundDrawable(mQueryTextEmptyBg);
3437010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                mQueryTextView.setHint(null);
3447010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            } else {
3457010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                if (mQueryTextNotEmptyBg == null) {
3467010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                    mQueryTextNotEmptyBg =
3477010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                            getResources().getDrawable(R.drawable.textfield_search_empty);
3487010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                }
3497010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                mQueryTextView.setBackgroundDrawable(mQueryTextNotEmptyBg);
3500a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood                Corpus corpus = getCorpus();
3510a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood                mQueryTextView.setHint(corpus == null ? "" : corpus.getHint());
3527010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            }
3537010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        } else {
3547010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            mQueryTextView.setBackgroundResource(R.drawable.textfield_search);
3557010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
3567010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
3577010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
3587010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private void updateSearchGoButton(boolean queryEmpty) {
3597010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        if (queryEmpty) {
3607010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            mSearchGoButton.setVisibility(View.GONE);
3617010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        } else {
3627010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            mSearchGoButton.setVisibility(View.VISIBLE);
3637010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
3647010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
3657010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
3667010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    protected void updateVoiceSearchButton(boolean queryEmpty) {
3673be3f12c41baa6c91ebb4fef366bd3d9bfcbc093Bjorn Bringert        if (shouldShowVoiceSearch(queryEmpty)
3683be3f12c41baa6c91ebb4fef366bd3d9bfcbc093Bjorn Bringert                && getVoiceSearch().shouldShowVoiceSearch(getCorpus())) {
3697010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            mVoiceSearchButton.setVisibility(View.VISIBLE);
3707010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            mQueryTextView.setPrivateImeOptions(IME_OPTION_NO_MICROPHONE);
3717010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        } else {
3727010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            mVoiceSearchButton.setVisibility(View.GONE);
3737010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            mQueryTextView.setPrivateImeOptions(null);
3747010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
3757010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
3767010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
3773be3f12c41baa6c91ebb4fef366bd3d9bfcbc093Bjorn Bringert    protected boolean shouldShowVoiceSearch(boolean queryEmpty) {
3783be3f12c41baa6c91ebb4fef366bd3d9bfcbc093Bjorn Bringert        return queryEmpty;
3793be3f12c41baa6c91ebb4fef366bd3d9bfcbc093Bjorn Bringert    }
3803be3f12c41baa6c91ebb4fef366bd3d9bfcbc093Bjorn Bringert
381c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert    /**
382c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert     * Hides the input method.
383c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert     */
384c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert    protected void hideInputMethod() {
385c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert        InputMethodManager imm = (InputMethodManager)
386c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert                getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
387c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert        if (imm != null) {
388c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert            imm.hideSoftInputFromWindow(getWindowToken(), 0);
389c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert        }
390c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert    }
391c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert
3928749e424d7645e708f238530621248abb567e3beBjorn Bringert    public abstract void considerHidingInputMethod();
3937010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
3947010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public void showInputMethodForQuery() {
3957010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mQueryTextView.showInputMethod();
3967010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
3977010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
398c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert    /**
399b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert     * Dismiss the activity if BACK is pressed when the search box is empty.
400b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert     */
401b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert    @Override
402b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert    public boolean dispatchKeyEventPreIme(KeyEvent event) {
403b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert        SearchActivity activity = getActivity();
404b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert        if (activity != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK
405b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert                && isQueryEmpty()) {
406b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert            KeyEvent.DispatcherState state = getKeyDispatcherState();
407b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert            if (state != null) {
408b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert                if (event.getAction() == KeyEvent.ACTION_DOWN
409b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert                        && event.getRepeatCount() == 0) {
410b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert                    state.startTracking(event, this);
411b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert                    return true;
412b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert                } else if (event.getAction() == KeyEvent.ACTION_UP
413b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert                        && !event.isCanceled() && state.isTracking(event)) {
414b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert                    hideInputMethod();
415b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert                    activity.onBackPressed();
416b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert                    return true;
417b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert                }
418b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert            }
419b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert        }
420b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert        return super.dispatchKeyEventPreIme(event);
421b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert    }
422b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert
423b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert    /**
4247010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     * If the input method is in fullscreen mode, and the selector corpus
4257010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     * is All or Web, use the web search suggestions as completions.
4267010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     */
4277010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    protected void updateInputMethodSuggestions() {
4287010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        InputMethodManager imm = (InputMethodManager)
4297010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
4307010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        if (imm == null || !imm.isFullscreenMode()) return;
4317010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        Suggestions suggestions = mSuggestionsAdapter.getSuggestions();
4327010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        if (suggestions == null) return;
4337010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        CompletionInfo[] completions = webSuggestionsToCompletions(suggestions);
4347010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        if (DBG) Log.d(TAG, "displayCompletions(" + Arrays.toString(completions) + ")");
4357010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        imm.displayCompletions(mQueryTextView, completions);
4367010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
4377010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
4387010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private CompletionInfo[] webSuggestionsToCompletions(Suggestions suggestions) {
4397010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        // TODO: This should also include include web search shortcuts
4407010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        CorpusResult cursor = suggestions.getWebResult();
4417010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        if (cursor == null) return null;
4427010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        int count = cursor.getCount();
4437010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        ArrayList<CompletionInfo> completions = new ArrayList<CompletionInfo>(count);
4447010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        boolean usingWebCorpus = isSearchCorpusWeb();
4457010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        for (int i = 0; i < count; i++) {
4467010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            cursor.moveTo(i);
4477010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            if (!usingWebCorpus || cursor.isWebSearchSuggestion()) {
4487010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                String text1 = cursor.getSuggestionText1();
4497010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                completions.add(new CompletionInfo(i, i, text1));
4507010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            }
4517010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
4527010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return completions.toArray(new CompletionInfo[completions.size()]);
4537010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
4547010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
4558b2936607176720172aee068abc5631bdf77e843Bjorn Bringert    protected void onSuggestionsChanged() {
4568b2936607176720172aee068abc5631bdf77e843Bjorn Bringert        updateInputMethodSuggestions();
4578b2936607176720172aee068abc5631bdf77e843Bjorn Bringert    }
4588b2936607176720172aee068abc5631bdf77e843Bjorn Bringert
4597010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    /**
4607010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     * Checks if the corpus used for typed searches is the web corpus.
4617010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     */
4627010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    protected boolean isSearchCorpusWeb() {
4637010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        Corpus corpus = getSearchCorpus();
4647010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return corpus != null && corpus.isWebCorpus();
4657010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
4667010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
467fd4a4cbc1143a734d357897531daa7105db6459bMathew Inwood    protected boolean onSuggestionKeyDown(SuggestionsAdapter<?> adapter,
46845f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood            long suggestionId, int keyCode, KeyEvent event) {
4697010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        // Treat enter or search as a click
4707010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        if (       keyCode == KeyEvent.KEYCODE_ENTER
4717010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                || keyCode == KeyEvent.KEYCODE_SEARCH
4727010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                || keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
4730a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood            if (adapter != null) {
47445f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood                adapter.onSuggestionClicked(suggestionId);
4757010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                return true;
4767010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            } else {
4777010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                return false;
4787010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            }
4797010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
4807010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
4817010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return false;
4827010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
4837010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
4847010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    protected boolean onSearchClicked(int method) {
4857010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        if (mSearchClickListener != null) {
4867010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            return mSearchClickListener.onSearchClicked(method);
4877010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
4887010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return false;
4897010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
4907010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
4917010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    /**
4927010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     * Filters the suggestions list when the search text changes.
4937010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     */
4947010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private class SearchTextWatcher implements TextWatcher {
4957010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public void afterTextChanged(Editable s) {
4967010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            boolean empty = s.length() == 0;
4977010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            if (empty != mQueryWasEmpty) {
4987010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                mQueryWasEmpty = empty;
4997010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                updateUi(empty);
5007010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            }
5017010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            if (mUpdateSuggestions) {
5027010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                if (mQueryListener != null) {
5037010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                    mQueryListener.onQueryChanged();
5047010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                }
5057010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            }
5067010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
5077010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
5087010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
5097010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
5107010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
5117010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public void onTextChanged(CharSequence s, int start, int before, int count) {
5127010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
5137010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
5147010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
5157010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    /**
5167010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     * Handles key events on the suggestions list view.
5177010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     */
5187010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    protected class SuggestionsViewKeyListener implements View.OnKeyListener {
5197010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public boolean onKey(View v, int keyCode, KeyEvent event) {
5207010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            if (event.getAction() == KeyEvent.ACTION_DOWN
52145f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood                    && v instanceof SuggestionsListView<?>) {
52245f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood                SuggestionsListView<?> listView = (SuggestionsListView<?>) v;
52345f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood                if (onSuggestionKeyDown(listView.getSuggestionsAdapter(),
52445f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood                        listView.getSelectedItemId(), keyCode, event)) {
5257010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                    return true;
5267010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                }
5277010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            }
5287010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            return forwardKeyToQueryTextView(keyCode, event);
5297010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
5307010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
5317010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
5327010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private class InputMethodCloser implements SuggestionsView.OnScrollListener {
5337010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
5347010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
5357010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                int totalItemCount) {
5367010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
5377010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
5387010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public void onScrollStateChanged(AbsListView view, int scrollState) {
5397010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            considerHidingInputMethod();
5407010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
5417010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
5427010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
5437010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    /**
5447010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     * Listens for clicks on the source selector.
5457010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     */
5467010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private class SearchGoButtonClickListener implements View.OnClickListener {
5477010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public void onClick(View view) {
5487010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            onSearchClicked(Logger.SEARCH_METHOD_BUTTON);
5497010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
5507010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
5517010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
5527010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    /**
553748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwood     * This class handles enter key presses in the query text view.
5547010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     */
555748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwood    private class QueryTextEditorActionListener implements OnEditorActionListener {
556748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwood        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
557748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwood            boolean consumed = false;
558748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwood            if (event != null) {
559748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwood                if (event.getAction() == KeyEvent.ACTION_UP) {
560748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwood                    consumed = onSearchClicked(Logger.SEARCH_METHOD_KEYBOARD);
561748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwood                } else if (event.getAction() == KeyEvent.ACTION_DOWN) {
562748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwood                    // we have to consume the down event so that we receive the up event too
563748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwood                    consumed = true;
564748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwood                }
5657010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            }
566748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwood            if (DBG) Log.d(TAG, "onEditorAction consumed=" + consumed);
567748a3cd7cb44de0aedb05e3c5d19989e2e52164fMathew Inwood            return consumed;
5687010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
5697010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
5707010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
5717010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    /**
5727010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     * Handles key events on the search and voice search buttons,
5737010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     * by refocusing to EditText.
5747010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     */
5757010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private class ButtonsKeyListener implements View.OnKeyListener {
5767010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public boolean onKey(View v, int keyCode, KeyEvent event) {
5777010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            return forwardKeyToQueryTextView(keyCode, event);
5787010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
5797010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
5807010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
5817010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private boolean forwardKeyToQueryTextView(int keyCode, KeyEvent event) {
58245f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood        if (!event.isSystem() && shouldForwardToQueryTextView(keyCode)) {
5837010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            if (DBG) Log.d(TAG, "Forwarding key to query box: " + event);
5847010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            if (mQueryTextView.requestFocus()) {
5857010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                return mQueryTextView.dispatchKeyEvent(event);
5867010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            }
5877010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
5887010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return false;
5897010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
5907010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
59145f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood    private boolean shouldForwardToQueryTextView(int keyCode) {
5927010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        switch (keyCode) {
5937010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            case KeyEvent.KEYCODE_DPAD_UP:
5947010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            case KeyEvent.KEYCODE_DPAD_DOWN:
5957010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            case KeyEvent.KEYCODE_DPAD_LEFT:
5967010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            case KeyEvent.KEYCODE_DPAD_RIGHT:
5977010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            case KeyEvent.KEYCODE_DPAD_CENTER:
59845f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood            case KeyEvent.KEYCODE_ENTER:
59945f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood            case KeyEvent.KEYCODE_SEARCH:
6007010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                return false;
60145f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood            default:
60245f42cab0664a8a23975e8913dbe77c1fd8ad86cMathew Inwood                return true;
6037010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
6047010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
6057010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
6067010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    /**
6077010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     * Hides the input method when the suggestions get focus.
6087010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert     */
6097010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private class SuggestListFocusListener implements OnFocusChangeListener {
6107010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public void onFocusChange(View v, boolean focused) {
6117010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            if (DBG) Log.d(TAG, "Suggestions focus change, now: " + focused);
6127010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            if (focused) {
6137010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                considerHidingInputMethod();
6147010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            }
6157010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
6167010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
6177010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
6187010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private class QueryTextViewFocusListener implements OnFocusChangeListener {
6197010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public void onFocusChange(View v, boolean focused) {
6207010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            if (DBG) Log.d(TAG, "Query focus change, now: " + focused);
6217010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            if (focused) {
6227010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                // The query box got focus, show the input method
6237010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                showInputMethodForQuery();
6247010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            }
6257010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
6267010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
6277010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
6287a0c3a7c6fdabce949b59e0a2c6ec1d44a140c24Mathew Inwood    protected class SuggestionsObserver extends DataSetObserver {
6297010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        @Override
6307010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public void onChanged() {
6318b2936607176720172aee068abc5631bdf77e843Bjorn Bringert            onSuggestionsChanged();
6327010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        }
6337010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
6347010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
6357010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public interface QueryListener {
6367010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        void onQueryChanged();
6377010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
6387010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
6397010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    public interface SearchClickListener {
6407010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        boolean onSearchClicked(int method);
6417010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    }
6427010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert
6432cbf1d099dbd04c612e3cba34a70293705730fa0Amith Yamasani    private class CloseClickListener implements OnClickListener {
6442cbf1d099dbd04c612e3cba34a70293705730fa0Amith Yamasani        public void onClick(View v) {
645b28dcd61d3aec036c6a2b51571d11453ff6eb671Bjorn Bringert            if (!isQueryEmpty()) {
6469e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood                mQueryTextView.setText("");
6479e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood            } else {
6489e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood                mExitClickListener.onClick(v);
6499e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood            }
6502cbf1d099dbd04c612e3cba34a70293705730fa0Amith Yamasani        }
6512cbf1d099dbd04c612e3cba34a70293705730fa0Amith Yamasani    }
652c36735de23beadc017c484596b551d7c4eaff289Bjorn Bringert}
653