SearchActivity.java revision d6b9bd42f22582a8ccec657bd6d715465de98ec9
13e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/*
23e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Copyright (C) 2009 The Android Open Source Project
33e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert *
43e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
53e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * you may not use this file except in compliance with the License.
63e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * You may obtain a copy of the License at
73e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert *
83e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert *      http://www.apache.org/licenses/LICENSE-2.0
93e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert *
103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * See the License for the specific language governing permissions and
143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * limitations under the License.
153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */
163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpackage com.android.quicksearchbox;
183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
193f71a11f8858b9164ca83e8d2f558dd8a8a5e2deBjorn Bringertimport com.android.common.Search;
20c5a3ecb62318a6be1d1a626a36b52829e989f740Bjorn Bringertimport com.android.quicksearchbox.ui.CorpusViewFactory;
21185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionClickListener;
227b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionSelectionListener;
23185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionsAdapter;
24883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringertimport com.android.quicksearchbox.ui.SuggestionsFooter;
25185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionsView;
26185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.app.Activity;
283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.app.SearchManager;
29dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringertimport android.content.DialogInterface;
303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.Intent;
31d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinneyimport android.graphics.drawable.Drawable;
32fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.net.Uri;
333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.os.Bundle;
3411234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringertimport android.os.Debug;
354ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringertimport android.os.Handler;
363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.Editable;
373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.TextUtils;
383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.TextWatcher;
393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.util.Log;
403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.KeyEvent;
413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.Menu;
423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.View;
43883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringertimport android.view.ViewGroup;
443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.View.OnFocusChangeListener;
453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.inputmethod.InputMethodManager;
46145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringertimport android.widget.AbsListView;
473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.widget.EditText;
483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.widget.ImageButton;
493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
5011234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringertimport java.io.File;
51e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringertimport java.util.Collection;
5247d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringertimport java.util.Collections;
5347d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringertimport java.util.List;
54ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/**
563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * The main activity for Quick Search Box. Shows the search UI.
573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert *
583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */
593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpublic class SearchActivity extends Activity {
603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
61b5fc08b7f16a32d3865f44b7f26d8aaa5304a2adBjorn Bringert    private static final boolean DBG = false;
620484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    private static final String TAG = "QSB.SearchActivity";
6311234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert    private static final boolean TRACE = false;
643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
65fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private static final String SCHEME_CORPUS = "qsb.corpus";
66fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
67fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public static final String INTENT_ACTION_QSB_AND_SELECT_CORPUS
68fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            = "com.android.quicksearchbox.action.QSB_AND_SELECT_CORPUS";
693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
70c15f386b167efb3f7559f2f7ee362497040b7fe6Bjorn Bringert    // The string used for privateImeOptions to identify to the IME that it should not show
71c15f386b167efb3f7559f2f7ee362497040b7fe6Bjorn Bringert    // a microphone button since one already exists in the search dialog.
72c15f386b167efb3f7559f2f7ee362497040b7fe6Bjorn Bringert    // TODO: This should move to android-common or something.
73c15f386b167efb3f7559f2f7ee362497040b7fe6Bjorn Bringert    private static final String IME_OPTION_NO_MICROPHONE = "nm";
74c15f386b167efb3f7559f2f7ee362497040b7fe6Bjorn Bringert
759ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    // Keys for the saved instance state.
76fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private static final String INSTANCE_KEY_CORPUS = "corpus";
779ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    private static final String INSTANCE_KEY_USER_QUERY = "query";
78713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
79f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    // Measures time from for last onCreate()/onNewIntent() call.
80f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    private LatencyTracker mStartLatencyTracker;
81ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    // Whether QSB is starting. True between the calls to onCreate()/onNewIntent() and onResume().
82ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private boolean mStarting;
83ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    // True if the user has taken some action, e.g. launching a search, voice search,
84ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    // or suggestions, since QSB was last started.
85ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private boolean mTookAction;
86ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
87f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    private CorpusSelectionDialog mCorpusSelectionDialog;
88f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert
89185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert    protected SuggestionsAdapter mSuggestionsAdapter;
90185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected EditText mQueryTextView;
92e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    // True if the query was empty on the previous call to updateQuery()
93e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    protected boolean mQueryWasEmpty = true;
943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected SuggestionsView mSuggestionsView;
96883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert    protected SuggestionsFooter mSuggestionsFooter;
973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected ImageButton mSearchGoButton;
993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected ImageButton mVoiceSearchButton;
100a576b1abd602c08dcf0d470facc43fac0243b07cBjorn Bringert    protected ImageButton mCorpusIndicator;
1013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private Launcher mLauncher;
1033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
104fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private Corpus mCorpus;
1052617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert    private Bundle mAppSearchData;
106713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    private boolean mUpdateSuggestions;
107713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    private String mUserQuery;
108713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    private boolean mSelectAll;
1093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
110d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood    private final Handler mHandler = new Handler();
111d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood    private final Runnable mUpdateSuggestionsTask = new Runnable() {
1124ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert        public void run() {
1134ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert            updateSuggestions(getQuery());
1144ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert        }
1154ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    };
1164ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert
117d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood    private final Runnable mShowInputMethodTask = new Runnable() {
118d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        public void run() {
119d98911178013162737fbba74387b51d2a08b0493Amith Yamasani            showInputMethodForQuery();
120d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        }
121d98911178013162737fbba74387b51d2a08b0493Amith Yamasani    };
122d98911178013162737fbba74387b51d2a08b0493Amith Yamasani
1233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /** Called when the activity is first created. */
1243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
1253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public void onCreate(Bundle savedInstanceState) {
12611234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        if (TRACE) startMethodTracing();
127ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        recordStartTime();
1283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "onCreate()");
1293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        super.onCreate(savedInstanceState);
130713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
131e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        setContentView(R.layout.search_activity);
1323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
133816804b67619af133860a1e28e92f58bc642260dBjorn Bringert        mSuggestionsAdapter = getQsbApplication().createSuggestionsAdapter();
134185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
1353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mQueryTextView = (EditText) findViewById(R.id.search_src_text);
1363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mSuggestionsView = (SuggestionsView) findViewById(R.id.suggestions);
137782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        mSuggestionsView.setSuggestionClickListener(new ClickHandler());
1387b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert        mSuggestionsView.setSuggestionSelectionListener(new SelectionHandler());
139145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert        mSuggestionsView.setOnScrollListener(new InputMethodCloser());
140713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        mSuggestionsView.setOnKeyListener(new SuggestionsViewKeyListener());
1417b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert        mSuggestionsView.setOnFocusChangeListener(new SuggestListFocusListener());
1423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
143883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert        mSuggestionsFooter = getQsbApplication().createSuggestionsFooter();
144dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert        ViewGroup footerFrame = (ViewGroup) findViewById(R.id.footer);
145dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert        mSuggestionsFooter.addToContainer(footerFrame);
146883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert
1473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mSearchGoButton = (ImageButton) findViewById(R.id.search_go_btn);
1483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mVoiceSearchButton = (ImageButton) findViewById(R.id.search_voice_btn);
149a576b1abd602c08dcf0d470facc43fac0243b07cBjorn Bringert        mCorpusIndicator = (ImageButton) findViewById(R.id.corpus_indicator);
1503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1519ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        mLauncher = new Launcher(this);
1523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
153782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        mQueryTextView.addTextChangedListener(new SearchTextWatcher());
154782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        mQueryTextView.setOnKeyListener(new QueryTextViewKeyListener());
1557b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert        mQueryTextView.setOnFocusChangeListener(new QueryTextViewFocusListener());
156782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
157fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        mCorpusIndicator.setOnClickListener(new CorpusIndicatorClickListener());
1582617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
159782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        mSearchGoButton.setOnClickListener(new SearchGoButtonClickListener());
160782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
161782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        mVoiceSearchButton.setOnClickListener(new VoiceSearchButtonClickListener());
1627be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert
1637be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        ButtonsKeyListener buttonsKeyListener = new ButtonsKeyListener();
1647be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        mSearchGoButton.setOnKeyListener(buttonsKeyListener);
1657be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        mVoiceSearchButton.setOnKeyListener(buttonsKeyListener);
166fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        mCorpusIndicator.setOnKeyListener(buttonsKeyListener);
167713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
1689ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        mUpdateSuggestions = true;
1699ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
1709ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // First get setup from intent
1719ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        Intent intent = getIntent();
1729ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        setupFromIntent(intent);
1739ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // Then restore any saved instance state
1749ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        restoreInstanceState(savedInstanceState);
1759ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
176713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        // Do this at the end, to avoid updating the list view when setSource()
177713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        // is called.
178713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        mSuggestionsView.setAdapter(mSuggestionsAdapter);
179dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert        mSuggestionsFooter.setAdapter(mSuggestionsAdapter);
1809ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    }
181713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
18211234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert    private void startMethodTracing() {
18311234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        File traceDir = getDir("traces", 0);
18411234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        String traceFile = new File(traceDir, "qsb.trace").getAbsolutePath();
18511234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        Debug.startMethodTracing(traceFile);
18611234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert    }
18711234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert
1889ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    @Override
1899ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    protected void onNewIntent(Intent intent) {
190ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        recordStartTime();
1919ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        setIntent(intent);
1929ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        setupFromIntent(intent);
1939ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    }
1949ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
195ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private void recordStartTime() {
196f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        mStartLatencyTracker = new LatencyTracker();
197ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mStarting = true;
198ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mTookAction = false;
199ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    }
200ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
2019ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    protected void restoreInstanceState(Bundle savedInstanceState) {
2029ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        if (savedInstanceState == null) return;
203fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        String corpusName = savedInstanceState.getString(INSTANCE_KEY_CORPUS);
2049ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        String query = savedInstanceState.getString(INSTANCE_KEY_USER_QUERY);
205fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        setCorpus(getCorpus(corpusName));
2069ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        setUserQuery(query);
207713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    }
208713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
209713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    @Override
2109ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    protected void onSaveInstanceState(Bundle outState) {
2119ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        super.onSaveInstanceState(outState);
2129ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // We don't save appSearchData, since we always get the value
2139ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // from the intent and the user can't change it.
214fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
215fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        String corpusName = mCorpus == null ? null : mCorpus.getName();
216fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        outState.putString(INSTANCE_KEY_CORPUS, corpusName);
2179ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        outState.putString(INSTANCE_KEY_USER_QUERY, mUserQuery);
218713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    }
219713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
220713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    private void setupFromIntent(Intent intent) {
221713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        if (DBG) Log.d(TAG, "setupFromIntent(" + intent.toUri(0) + ")");
222fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        Corpus corpus = getCorpusFromUri(intent.getData());
2232617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        String query = intent.getStringExtra(SearchManager.QUERY);
2242617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        Bundle appSearchData = intent.getBundleExtra(SearchManager.APP_DATA);
2252617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
226fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        setCorpus(corpus);
2272617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        setUserQuery(query);
228154017089860da89ec020ed37e502d194253cc67Bjorn Bringert        mSelectAll = intent.getBooleanExtra(SearchManager.EXTRA_SELECT_QUERY, false);
229c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        mAppSearchData = appSearchData;
2302617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
23111c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert        if (startedIntoCorpusSelectionDialog()) {
23241fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert            showCorpusSelectionDialog();
2332617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        }
2349ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    }
2359ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
23611c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert    public boolean startedIntoCorpusSelectionDialog() {
23711c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert        return INTENT_ACTION_QSB_AND_SELECT_CORPUS.equals(getIntent().getAction());
23811c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert    }
23911c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert
240dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    /**
241dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert     * Removes corpus selector intent action, so that BACK works normally after
242dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert     * dismissing and reopening the corpus selector.
243dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert     */
244dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    private void clearStartedIntoCorpusSelectionDialog() {
245dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        Intent oldIntent = getIntent();
246dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        if (SearchActivity.INTENT_ACTION_QSB_AND_SELECT_CORPUS.equals(oldIntent.getAction())) {
247dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            Intent newIntent = new Intent(oldIntent);
248dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            newIntent.setAction(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
249dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            setIntent(newIntent);
250dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        }
251dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    }
252dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert
253fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public static Uri getCorpusUri(Corpus corpus) {
254fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (corpus == null) return null;
255fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return new Uri.Builder()
256fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                .scheme(SCHEME_CORPUS)
257fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                .authority(corpus.getName())
258fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                .build();
259fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
260fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
261fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private Corpus getCorpusFromUri(Uri uri) {
262fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (uri == null) return null;
263fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (!SCHEME_CORPUS.equals(uri.getScheme())) return null;
264fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        String name = uri.getAuthority();
265fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return getCorpus(name);
266fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
267fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
268fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private Corpus getCorpus(String sourceName) {
2690ccab5903ba2c64ec4cdd33dbcea91b1e279d556Bjorn Bringert        if (sourceName == null) return null;
270fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        Corpus corpus = getCorpora().getCorpus(sourceName);
271fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (corpus == null) {
272fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            Log.w(TAG, "Unknown corpus " + sourceName);
2739ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert            return null;
274713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        }
275fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return corpus;
276713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    }
277713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
278fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private void setCorpus(Corpus corpus) {
279fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (DBG) Log.d(TAG, "setCorpus(" + corpus + ")");
280fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        mCorpus = corpus;
2819ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        Drawable sourceIcon;
282fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (corpus == null) {
283c5a3ecb62318a6be1d1a626a36b52829e989f740Bjorn Bringert            sourceIcon = getCorpusViewFactory().getGlobalSearchIcon();
284713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        } else {
285fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            sourceIcon = corpus.getCorpusIcon();
286713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        }
287fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        mSuggestionsAdapter.setCorpus(corpus);
288a576b1abd602c08dcf0d470facc43fac0243b07cBjorn Bringert        mCorpusIndicator.setImageDrawable(sourceIcon);
2893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
2905691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert        updateUi(getQuery().length() == 0);
2910484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    }
2920484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
2933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private QsbApplication getQsbApplication() {
2943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return (QsbApplication) getApplication();
2953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
2963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
2974ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    private Config getConfig() {
2984ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert        return getQsbApplication().getConfig();
2994ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    }
3004ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert
301fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private Corpora getCorpora() {
302fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return getQsbApplication().getCorpora();
303fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
304fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
3053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private ShortcutRepository getShortcutRepository() {
3063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return getQsbApplication().getShortcutRepository();
3073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
309ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private SuggestionsProvider getSuggestionsProvider() {
31047d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert        return getQsbApplication().getSuggestionsProvider();
31147d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert    }
31247d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert
31347d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert    private CorpusRanker getCorpusRanker() {
31447d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert        return getQsbApplication().getCorpusRanker();
3153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
317c5a3ecb62318a6be1d1a626a36b52829e989f740Bjorn Bringert    private CorpusViewFactory getCorpusViewFactory() {
318c5a3ecb62318a6be1d1a626a36b52829e989f740Bjorn Bringert        return getQsbApplication().getCorpusViewFactory();
319185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert    }
320185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
321ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private Logger getLogger() {
322ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        return getQsbApplication().getLogger();
323ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    }
324ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
3253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
3263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void onDestroy() {
3273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "onDestroy()");
3283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        super.onDestroy();
329dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert        mSuggestionsFooter.setAdapter(null);
330185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert        mSuggestionsView.setAdapter(null);  // closes mSuggestionsAdapter
3313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
3333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
3343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void onStop() {
3359ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        if (DBG) Log.d(TAG, "onStop()");
336f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        if (!mTookAction) {
337f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            // TODO: This gets logged when starting other activities, e.g. by opening he search
338f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            // settings, or clicking a notification in the status bar.
339f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            getLogger().logExit(getCurrentSuggestions(), getQuery().length());
340f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        }
3419ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // Close all open suggestion cursors. The query will be redone in onResume()
3423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        // if we come back to this activity.
343185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert        mSuggestionsAdapter.setSuggestions(null);
34494e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney        getQsbApplication().getShortcutRefresher().reset();
345f69873ae02e6d8f8a550f5fa43b5b1f2cbea96ffBjorn Bringert        dismissCorpusSelectionDialog();
3463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        super.onStop();
3473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
3493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
350b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert    protected void onResume() {
3519ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        if (DBG) Log.d(TAG, "onResume()");
352b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert        super.onResume();
3539ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        setQuery(mUserQuery, mSelectAll);
3549ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // Only select everything the first time after creating the activity.
3559ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        mSelectAll = false;
35611234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        updateSuggestionsBuffered();
357dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        if (!isCorpusSelectionDialogShowing()) {
358dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            mQueryTextView.requestFocus();
359dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        }
36011234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        if (TRACE) Debug.stopMethodTracing();
361b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert    }
362b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert
363b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert    @Override
3643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public boolean onCreateOptionsMenu(Menu menu) {
3653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        super.onCreateOptionsMenu(menu);
36626d85260316193a1aeff5d407d4f32f5297be012Bjorn Bringert        SearchSettings.addSearchSettingsMenuItem(this, menu);
3673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return true;
3683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
370d98911178013162737fbba74387b51d2a08b0493Amith Yamasani    @Override
371d98911178013162737fbba74387b51d2a08b0493Amith Yamasani    public void onWindowFocusChanged(boolean hasFocus) {
372d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        super.onWindowFocusChanged(hasFocus);
373d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        if (hasFocus) {
374d98911178013162737fbba74387b51d2a08b0493Amith Yamasani            // Launch the IME after a bit
375d98911178013162737fbba74387b51d2a08b0493Amith Yamasani            mHandler.postDelayed(mShowInputMethodTask, 0);
376d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        }
377d98911178013162737fbba74387b51d2a08b0493Amith Yamasani    }
378d98911178013162737fbba74387b51d2a08b0493Amith Yamasani
3799ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    /**
3809ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert     * Sets the query as typed by the user. Does not update the suggestions
3819ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert     * or the text in the query box.
3829ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert     */
3839ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    protected void setUserQuery(String userQuery) {
3849ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        if (userQuery == null) userQuery = "";
3859ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        mUserQuery = userQuery;
3869ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    }
3879ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
388713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    protected String getQuery() {
3893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        CharSequence q = mQueryTextView.getText();
3903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return q == null ? "" : q.toString();
3913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
3933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
3943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Restores the query entered by the user.
3953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
3963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private void restoreUserQuery() {
3973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "Restoring query to '" + mUserQuery + "'");
3983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        setQuery(mUserQuery, false);
3993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
4003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
4013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
4023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Sets the text in the query box. Does not update the suggestions,
4033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * and does not change the saved user-entered query.
4043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * {@link #restoreUserQuery()} will restore the query to the last
4053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * user-entered query.
4063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
4073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private void setQuery(String query, boolean selectAll) {
4083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mUpdateSuggestions = false;
4093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mQueryTextView.setText(query);
4103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        setTextSelection(selectAll);
4113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mUpdateSuggestions = true;
4123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
4133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
4143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
4153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Sets the text selection in the query text view.
4163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     *
4173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * @param selectAll If {@code true}, selects the entire query.
4183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     *        If {@false}, no characters are selected, and the cursor is placed
4193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     *        at the end of the query.
4203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
4213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private void setTextSelection(boolean selectAll) {
4223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (selectAll) {
4235691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert            mQueryTextView.selectAll();
4243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        } else {
4253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            mQueryTextView.setSelection(mQueryTextView.length());
4263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
4273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
4283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
4295691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert    private void updateUi(boolean queryEmpty) {
4305691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert        updateQueryTextView(queryEmpty);
4315691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert        updateSearchGoButton(queryEmpty);
4325691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert        updateVoiceSearchButton(queryEmpty);
4335691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert    }
4345691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert
435e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    private void updateQueryTextView(boolean queryEmpty) {
436e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        if (queryEmpty) {
4375691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert            if (mCorpus == null || mCorpus.isWebCorpus()) {
4385691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert                mQueryTextView.setBackgroundResource(R.drawable.textfield_search_empty_google);
4395691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert                mQueryTextView.setHint(null);
4405691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert            } else {
4415691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert                mQueryTextView.setBackgroundResource(R.drawable.textfield_search_empty);
4425691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert                mQueryTextView.setHint(mCorpus.getHint());
4435691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert            }
444e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        } else {
445e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            mQueryTextView.setBackgroundResource(R.drawable.textfield_search);
446e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        }
447e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    }
448e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert
449e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    private void updateSearchGoButton(boolean queryEmpty) {
450e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        if (queryEmpty) {
451e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            mSearchGoButton.setVisibility(View.GONE);
452e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        } else {
453e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            mSearchGoButton.setVisibility(View.VISIBLE);
454e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        }
455e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    }
456e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert
457e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    protected void updateVoiceSearchButton(boolean queryEmpty) {
458c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        if (queryEmpty && mLauncher.shouldShowVoiceSearch(mCorpus)) {
459e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            mVoiceSearchButton.setVisibility(View.VISIBLE);
460e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            mQueryTextView.setPrivateImeOptions(IME_OPTION_NO_MICROPHONE);
461e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        } else {
462e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            mVoiceSearchButton.setVisibility(View.GONE);
463e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            mQueryTextView.setPrivateImeOptions(null);
464e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        }
465e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    }
466e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert
46741fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert    protected void showCorpusSelectionDialog() {
468f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        if (mCorpusSelectionDialog == null) {
469f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            mCorpusSelectionDialog = new CorpusSelectionDialog(this);
470f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            mCorpusSelectionDialog.setOwnerActivity(this);
471dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            mCorpusSelectionDialog.setOnDismissListener(new CorpusSelectorDismissListener());
472f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            mCorpusSelectionDialog.setOnCorpusSelectedListener(new CorpusSelectionListener());
4732617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        }
474f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        mCorpusSelectionDialog.show(mCorpus);
4752617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert    }
4762617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
477dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    protected boolean isCorpusSelectionDialogShowing() {
478dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        return mCorpusSelectionDialog != null && mCorpusSelectionDialog.isShowing();
479dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    }
480dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert
481f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    protected void dismissCorpusSelectionDialog() {
482f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        if (mCorpusSelectionDialog != null) {
483f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            mCorpusSelectionDialog.dismiss();
4842617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        }
4852617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert    }
4862617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
487ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    protected void onSearchClicked(int method) {
4883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        String query = getQuery();
4893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "Search clicked, query=" + query);
490eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert
491eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert        // Don't do empty queries
492eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert        if (TextUtils.getTrimmedLength(query) == 0) return;
493eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert
494535931433926d342c6277034cad91143ae28b72dBjorn Bringert        Corpus searchCorpus = mLauncher.getSearchCorpus(getCorpora(), mCorpus);
495c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        if (searchCorpus == null) return;
496c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
497ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mTookAction = true;
498c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
499c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Log search start
500fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        getLogger().logSearch(mCorpus, method, query.length());
501c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
502c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Create shortcut
503c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        SuggestionData searchShortcut = searchCorpus.createSearchShortcut(query);
504c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        if (searchShortcut != null) {
505c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert            DataSuggestionCursor cursor = new DataSuggestionCursor(query);
506c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert            cursor.add(searchShortcut);
507c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert            getShortcutRepository().reportClick(cursor, 0);
508c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        }
509c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
510c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Start search
511c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        Intent intent = searchCorpus.createSearchIntent(query, mAppSearchData);
512c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        mLauncher.launchIntent(intent);
5133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
5143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
5153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void onVoiceSearchClicked() {
5163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "Voice Search clicked");
517535931433926d342c6277034cad91143ae28b72dBjorn Bringert        Corpus searchCorpus = mLauncher.getSearchCorpus(getCorpora(), mCorpus);
518c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        if (searchCorpus == null) return;
519c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
520535931433926d342c6277034cad91143ae28b72dBjorn Bringert        mTookAction = true;
521535931433926d342c6277034cad91143ae28b72dBjorn Bringert
522c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Log voice search start
523c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        getLogger().logVoiceSearch(searchCorpus);
524ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
525c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Start voice search
526c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        Intent intent = searchCorpus.createVoiceSearchIntent(mAppSearchData);
527c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        mLauncher.launchIntent(intent);
528c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert    }
529c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
530e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringert    protected SuggestionCursor getCurrentSuggestions() {
531fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return mSuggestionsAdapter.getCurrentSuggestions();
532782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    }
533782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
534fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    protected boolean launchSuggestion(int position) {
5356f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert        SuggestionCursor suggestions = getCurrentSuggestions();
5366f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert        if (position < 0 || position >= suggestions.getCount()) {
5376f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert            Log.w(TAG, "Tried to launch invalid suggestion " + position);
5386f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert            return false;
5396f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert        }
5406f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert
541fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (DBG) Log.d(TAG, "Launching suggestion " + position);
542ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mTookAction = true;
543e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringert
544c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Log suggestion click
545e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringert        Collection<Corpus> corpora = mSuggestionsAdapter.getSuggestions().getIncludedCorpora();
546fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        getLogger().logSuggestionClick(position, suggestions, corpora);
547ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
548c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Create shortcut
549fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        getShortcutRepository().reportClick(suggestions, position);
550c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
551c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Launch intent
552c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        Intent intent = mLauncher.getSuggestionIntent(suggestions, position, mAppSearchData);
553c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        mLauncher.launchIntent(intent);
554c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
5553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return true;
5563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
5573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
558fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    protected boolean onSuggestionLongClicked(int position) {
559fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (DBG) Log.d(TAG, "Long clicked on suggestion " + position);
5603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return false;
5613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
5623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
563fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    protected boolean onSuggestionKeyDown(int position, int keyCode, KeyEvent event) {
564782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        // Treat enter or search as a click
565782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH) {
566fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            return launchSuggestion(position);
567782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        }
568782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
5696f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert        if (keyCode == KeyEvent.KEYCODE_DPAD_UP && position == 0) {
5707b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            // Moved up from the top suggestion, restore the user query and focus query box
5717b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            if (DBG) Log.d(TAG, "Up and out");
5727b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            restoreUserQuery();
5737b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            return false;  // let the framework handle the move
5747b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert        }
5757b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert
5767b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert        if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT
5777b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert                || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
5787b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            // Moved left / right from a suggestion, keep current query, move
5797b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            // focus to query box, and move cursor to far left / right
5807b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            if (DBG) Log.d(TAG, "Left/right on a suggestion");
5814afd6f1587b1c2f3686190d55f1640ecfba03699Bjorn Bringert            String query = getQuery();
5824afd6f1587b1c2f3686190d55f1640ecfba03699Bjorn Bringert            int cursorPos = (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) ? 0 : query.length();
5837b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            mQueryTextView.setSelection(cursorPos);
5847b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            mQueryTextView.requestFocus();
5854afd6f1587b1c2f3686190d55f1640ecfba03699Bjorn Bringert            updateSuggestions(query);
5867b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            return true;
5877b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert        }
5887b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert
589782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        return false;
590782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    }
591782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
5923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void onSourceSelected() {
5933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "No suggestion selected");
5943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        restoreUserQuery();
5953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
5963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
597782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    protected int getSelectedPosition() {
598782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        return mSuggestionsView.getSelectedPosition();
599782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    }
600782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
6013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
6023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Hides the input method.
6033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
6043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void hideInputMethod() {
6053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
6063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (imm != null) {
6073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            imm.hideSoftInputFromWindow(mQueryTextView.getWindowToken(), 0);
6083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
6093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
6103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
6117b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert    protected void showInputMethodForQuery() {
6127b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert        InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
6137b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert        if (imm != null) {
614d98911178013162737fbba74387b51d2a08b0493Amith Yamasani            imm.showSoftInput(mQueryTextView, 0);
6157b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert        }
6167b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert    }
6177b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert
6183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
6193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Hides the input method when the suggestions get focus.
6203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
6213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private class SuggestListFocusListener implements OnFocusChangeListener {
6223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        public void onFocusChange(View v, boolean focused) {
6237b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            if (DBG) Log.d(TAG, "Suggestions focus change, now: " + focused);
6247b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            if (focused) {
6257b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert                // The suggestions list got focus, hide the input method
6267b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert                hideInputMethod();
6277b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            }
6287b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert        }
6297b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert    }
6307b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert
6317b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert    private class QueryTextViewFocusListener implements OnFocusChangeListener {
6327b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert        public void onFocusChange(View v, boolean focused) {
6337b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            if (DBG) Log.d(TAG, "Query focus change, now: " + focused);
6347b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            if (focused) {
635dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert                // The query box got focus, show the input method
6367b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert                showInputMethodForQuery();
6373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            }
6383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
6393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
6403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
64147d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert    private List<Corpus> getCorporaToQuery() {
64247d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert        if (mCorpus == null) {
64347d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert            return getCorpusRanker().getRankedCorpora();
64447d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert        } else {
64547d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert            return Collections.singletonList(mCorpus);
64647d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert        }
64747d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert    }
64847d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert
649e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney    private int getMaxSuggestions() {
650e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney        Config config = getConfig();
651e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney        return mCorpus == null
652e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney                ? config.getMaxPromotedSuggestions()
653e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney                : config.getMaxResultsPerSource();
654e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney    }
655e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney
6564ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    private void updateSuggestionsBuffered() {
657d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        mHandler.removeCallbacks(mUpdateSuggestionsTask);
6584ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert        long delay = getConfig().getTypingUpdateSuggestionsDelayMillis();
659d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        mHandler.postDelayed(mUpdateSuggestionsTask, delay);
6604ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    }
6614ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert
6623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private void updateSuggestions(String query) {
66311234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        // Log start latency if this is the first suggestions update
66411234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        if (mStarting) {
66511234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert            mStarting = false;
66611234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert            String source = getIntent().getStringExtra(Search.SOURCE);
66711234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert            List<Corpus> rankedCorpora = getCorpusRanker().getRankedCorpora();
66811234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert            int latency = mStartLatencyTracker.getLatency();
66911234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert            getLogger().logStart(latency, source, mCorpus, rankedCorpora);
67011234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        }
67111234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert
6723d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney        query = ltrim(query);
67347d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert        List<Corpus> corporaToQuery = getCorporaToQuery();
674e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney        Suggestions suggestions = getSuggestionsProvider().getSuggestions(
675e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney                query, corporaToQuery, getMaxSuggestions());
676185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert        mSuggestionsAdapter.setSuggestions(suggestions);
6773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
6783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
6797be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert    private boolean forwardKeyToQueryTextView(int keyCode, KeyEvent event) {
6807be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        if (!event.isSystem() && !isDpadKey(keyCode)) {
6817be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            if (DBG) Log.d(TAG, "Forwarding key to query box: " + event);
6827be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            if (mQueryTextView.requestFocus()) {
6837be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert                return mQueryTextView.dispatchKeyEvent(event);
6847be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            }
6857be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        }
6867be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        return false;
6877be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert    }
6887be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert
6897be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert    private boolean isDpadKey(int keyCode) {
6907be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        switch (keyCode) {
6917be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            case KeyEvent.KEYCODE_DPAD_UP:
6927be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            case KeyEvent.KEYCODE_DPAD_DOWN:
6937be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            case KeyEvent.KEYCODE_DPAD_LEFT:
6947be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            case KeyEvent.KEYCODE_DPAD_RIGHT:
6957be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            case KeyEvent.KEYCODE_DPAD_CENTER:
6967be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert                return true;
6977be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            default:
6987be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert                return false;
6997be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        }
7007be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert    }
7017be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert
7023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
7033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Filters the suggestions list when the search text changes.
7043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
7053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private class SearchTextWatcher implements TextWatcher {
7063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        public void afterTextChanged(Editable s) {
707e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            boolean empty = s.length() == 0;
708e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            if (empty != mQueryWasEmpty) {
709e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert                mQueryWasEmpty = empty;
7105691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert                updateUi(empty);
711e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            }
7123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            if (mUpdateSuggestions) {
7133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert                String query = s == null ? "" : s.toString();
7149ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert                setUserQuery(query);
7154ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert                updateSuggestionsBuffered();
7163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            }
7173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
7183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
7193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
7203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
7213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
7223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        public void onTextChanged(CharSequence s, int start, int before, int count) {
7233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
7243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
7253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
7263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
7273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Handles non-text keys in the query text view.
7283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
7293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private class QueryTextViewKeyListener implements View.OnKeyListener {
7303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        public boolean onKey(View view, int keyCode, KeyEvent event) {
7313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            // Handle IME search action key
7323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) {
733ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert                onSearchClicked(Logger.SEARCH_METHOD_KEYBOARD);
734d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood                // if no action was taken, consume the key event so that the keyboard
735d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood                // remains on screen.
736d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood                return !mTookAction;
7373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            }
7383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            return false;
7393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
7403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
7413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
742782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    /**
743782dd228e78e9294692d639597f96c26283968bbBjorn Bringert     * Handles key events on the search and voice search buttons,
744782dd228e78e9294692d639597f96c26283968bbBjorn Bringert     * by refocusing to EditText.
745782dd228e78e9294692d639597f96c26283968bbBjorn Bringert     */
746782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    private class ButtonsKeyListener implements View.OnKeyListener {
747782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        public boolean onKey(View v, int keyCode, KeyEvent event) {
7487be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            return forwardKeyToQueryTextView(keyCode, event);
749782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        }
750782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    }
751782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
752782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    /**
753782dd228e78e9294692d639597f96c26283968bbBjorn Bringert     * Handles key events on the suggestions list view.
754782dd228e78e9294692d639597f96c26283968bbBjorn Bringert     */
755713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    private class SuggestionsViewKeyListener implements View.OnKeyListener {
756782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        public boolean onKey(View v, int keyCode, KeyEvent event) {
757782dd228e78e9294692d639597f96c26283968bbBjorn Bringert            if (event.getAction() == KeyEvent.ACTION_DOWN) {
758fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                int position = getSelectedPosition();
759fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                if (onSuggestionKeyDown(position, keyCode, event)) {
7607be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert                        return true;
761782dd228e78e9294692d639597f96c26283968bbBjorn Bringert                }
762782dd228e78e9294692d639597f96c26283968bbBjorn Bringert            }
7637be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            return forwardKeyToQueryTextView(keyCode, event);
764782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        }
765782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    }
766782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
767145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert    private class InputMethodCloser implements SuggestionsView.OnScrollListener {
768145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert
769145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
770145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert                int totalItemCount) {
771145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert        }
772145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert
773145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert        public void onScrollStateChanged(AbsListView view, int scrollState) {
774185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert            hideInputMethod();
775185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert        }
776185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert    }
777185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
778185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert    private class ClickHandler implements SuggestionClickListener {
779fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert       public void onSuggestionClicked(int position) {
780fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert           launchSuggestion(position);
7813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert       }
7823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
783fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert       public boolean onSuggestionLongClicked(int position) {
784fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert           return SearchActivity.this.onSuggestionLongClicked(position);
785713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert       }
786145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert
787145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert       public void onSuggestionQueryRefineClicked(int position) {
788145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert           if (DBG) Log.d(TAG, "query refine clicked, pos " + position);
789145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert           SuggestionCursor suggestions = getCurrentSuggestions();
790145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert           if (suggestions != null) {
791145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert               suggestions.moveTo(position);
792145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert               String query = suggestions.getSuggestionQuery();
793145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert               if (!TextUtils.isEmpty(query)) {
794145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert                   query += " ";
795145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert                   setUserQuery(query);
796145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert                   setQuery(query, false);
797145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert                   updateSuggestions(query);
798145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert               }
799145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert           }
800145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert       }
8013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
8023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
8037b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert    private class SelectionHandler implements SuggestionSelectionListener {
804fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        public void onSuggestionSelected(int position) {
805e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringert            SuggestionCursor suggestions = getCurrentSuggestions();
806fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            suggestions.moveTo(position);
807fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            String displayQuery = suggestions.getSuggestionDisplayQuery();
808fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            if (TextUtils.isEmpty(displayQuery)) {
809fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                restoreUserQuery();
810fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            } else {
811fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                setQuery(displayQuery, false);
812fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            }
813fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        }
814fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
815fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        public void onNothingSelected() {
816fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                // This happens when a suggestion has been selected with the
817fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                // dpad / trackball and then a different UI element is touched.
818fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                // Do nothing, since we want to keep the query of the selection
819fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                // in the search box.
8207b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert        }
8217b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert    }
8227b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert
8233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
8242617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert     * Listens for clicks on the source selector.
8253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
8263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private class SearchGoButtonClickListener implements View.OnClickListener {
8273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        public void onClick(View view) {
828ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert            onSearchClicked(Logger.SEARCH_METHOD_BUTTON);
8293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
8303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
8313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
8323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
8332617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert     * Listens for clicks on the search button.
8342617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert     */
835fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private class CorpusIndicatorClickListener implements View.OnClickListener {
8362617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        public void onClick(View view) {
83741fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert            showCorpusSelectionDialog();
8382617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        }
839f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    }
840f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert
841dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    private class CorpusSelectorDismissListener implements DialogInterface.OnDismissListener {
842dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        public void onDismiss(DialogInterface dialog) {
843dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            if (DBG) Log.d(TAG, "Corpus selector dismissed");
844dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            clearStartedIntoCorpusSelectionDialog();
845dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        }
846dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    }
847dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert
848f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    private class CorpusSelectionListener
849f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            implements CorpusSelectionDialog.OnCorpusSelectedListener {
850f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        public void onCorpusSelected(Corpus corpus) {
851f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            setCorpus(corpus);
852f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            updateSuggestions(getQuery());
853f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            mQueryTextView.requestFocus();
854dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            showInputMethodForQuery();
855f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        }
8562617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert    }
8572617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
8582617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert    /**
8593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Listens for clicks on the voice search button.
8603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
8613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private class VoiceSearchButtonClickListener implements View.OnClickListener {
8623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        public void onClick(View view) {
8633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            onVoiceSearchClicked();
8643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
8653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
8663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
8673d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney    private static String ltrim(String text) {
8683d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney        int start = 0;
8693d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney        int length = text.length();
8703d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney        while (start < length && Character.isWhitespace(text.charAt(start))) {
8713d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney            start++;
8723d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney        }
8733d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney        return start > 0 ? text.substring(start, length) : text;
8743d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney    }
8753d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney
8763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert}
877