SearchActivity.java revision aa7d79792baca59eb7afe00ea27abc5176ddd34b
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;
21014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringertimport com.android.quicksearchbox.ui.QueryTextView;
22185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionClickListener;
23185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionsAdapter;
24185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionsView;
253a7125b39b72f7417684c4d3040abeb4a81bd6b3Bjorn Bringertimport com.google.common.base.CharMatcher;
26185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.app.Activity;
283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.app.SearchManager;
29dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringertimport android.content.DialogInterface;
303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.Intent;
3121bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringertimport android.database.DataSetObserver;
32d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinneyimport android.graphics.drawable.Drawable;
33fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.net.Uri;
343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.os.Bundle;
3511234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringertimport android.os.Debug;
364ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringertimport android.os.Handler;
373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.Editable;
383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.TextUtils;
393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.TextWatcher;
403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.util.Log;
413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.KeyEvent;
423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.Menu;
433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.View;
443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.View.OnFocusChangeListener;
45014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringertimport android.view.inputmethod.CompletionInfo;
463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.inputmethod.InputMethodManager;
47145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringertimport android.widget.AbsListView;
483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.widget.ImageButton;
49848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasaniimport android.widget.ImageView;
503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
5111234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringertimport java.io.File;
52014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringertimport java.util.ArrayList;
53014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringertimport java.util.Arrays;
545f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringertimport java.util.Set;
55ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/**
573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * The main activity for Quick Search Box. Shows the search UI.
583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert *
593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */
603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpublic class SearchActivity extends Activity {
613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
62754cb6b769c5955fc707a6c5ab6689b64df102b3Mathew Inwood    private static final boolean DBG = false;
630484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    private static final String TAG = "QSB.SearchActivity";
6411234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert    private static final boolean TRACE = false;
653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
66fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private static final String SCHEME_CORPUS = "qsb.corpus";
67fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
68fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public static final String INTENT_ACTION_QSB_AND_SELECT_CORPUS
69fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            = "com.android.quicksearchbox.action.QSB_AND_SELECT_CORPUS";
703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
71c15f386b167efb3f7559f2f7ee362497040b7fe6Bjorn Bringert    // The string used for privateImeOptions to identify to the IME that it should not show
72c15f386b167efb3f7559f2f7ee362497040b7fe6Bjorn Bringert    // a microphone button since one already exists in the search dialog.
73c15f386b167efb3f7559f2f7ee362497040b7fe6Bjorn Bringert    // TODO: This should move to android-common or something.
74c15f386b167efb3f7559f2f7ee362497040b7fe6Bjorn Bringert    private static final String IME_OPTION_NO_MICROPHONE = "nm";
75c15f386b167efb3f7559f2f7ee362497040b7fe6Bjorn Bringert
769ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    // Keys for the saved instance state.
77fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private static final String INSTANCE_KEY_CORPUS = "corpus";
78839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert    private static final String INSTANCE_KEY_QUERY = "query";
79713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
80f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    // Measures time from for last onCreate()/onNewIntent() call.
81f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    private LatencyTracker mStartLatencyTracker;
82ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    // Whether QSB is starting. True between the calls to onCreate()/onNewIntent() and onResume().
83ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private boolean mStarting;
84ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    // True if the user has taken some action, e.g. launching a search, voice search,
85ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    // or suggestions, since QSB was last started.
86ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private boolean mTookAction;
87ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
88f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    private CorpusSelectionDialog mCorpusSelectionDialog;
89f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert
90185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert    protected SuggestionsAdapter mSuggestionsAdapter;
91185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
92848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    // The list adapter for showing results other than query completion
93848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    // suggestions
94848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected SuggestionsAdapter mResultsAdapter;
95848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
9621bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    private CorporaObserver mCorporaObserver;
9721bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert
98014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert    protected QueryTextView mQueryTextView;
99e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    // True if the query was empty on the previous call to updateQuery()
100e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    protected boolean mQueryWasEmpty = true;
1012dfefcf67c7c28c8337725ef30d623a47638b374Mathew Inwood    protected Drawable mQueryTextEmptyBg;
1022dfefcf67c7c28c8337725ef30d623a47638b374Mathew Inwood    protected Drawable mQueryTextNotEmptyBg;
1033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected SuggestionsView mSuggestionsView;
1053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
106848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    // View that shows the results other than the query completions
107848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected SuggestionsView mResultsView;
108848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
109d5cd9612d6937dfb174bfe6f4e486f283ef557e9Mathew Inwood    protected boolean mSeparateResults;
110d5cd9612d6937dfb174bfe6f4e486f283ef557e9Mathew Inwood
1113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected ImageButton mSearchGoButton;
1123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected ImageButton mVoiceSearchButton;
11336cdac7349a76aa1db70ed7e8fa554ed54ad639dBjorn Bringert    protected ImageButton mCorpusIndicator;
1143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
115848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected ImageView mSettingsButton;
116848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
117fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private Corpus mCorpus;
1182617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert    private Bundle mAppSearchData;
119713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    private boolean mUpdateSuggestions;
1203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
121d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood    private final Handler mHandler = new Handler();
122d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood    private final Runnable mUpdateSuggestionsTask = new Runnable() {
1234ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert        public void run() {
1244ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert            updateSuggestions(getQuery());
1254ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert        }
1264ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    };
1274ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert
128d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood    private final Runnable mShowInputMethodTask = new Runnable() {
129d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        public void run() {
130d98911178013162737fbba74387b51d2a08b0493Amith Yamasani            showInputMethodForQuery();
131d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        }
132d98911178013162737fbba74387b51d2a08b0493Amith Yamasani    };
133d98911178013162737fbba74387b51d2a08b0493Amith Yamasani
1343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /** Called when the activity is first created. */
1353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
1363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public void onCreate(Bundle savedInstanceState) {
13711234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        if (TRACE) startMethodTracing();
138ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        recordStartTime();
1393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "onCreate()");
1403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        super.onCreate(savedInstanceState);
141713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
1426ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert        setContentView();
143aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood
14466ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood        SuggestListFocusListener suggestionFocusListener = new SuggestListFocusListener();
145aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood        SuggestionsViewKeyListener suggestionViewKeyListener = new SuggestionsViewKeyListener();
146aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood        InputMethodCloser imeCloser = new InputMethodCloser();
147185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
148014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        mQueryTextView = (QueryTextView) findViewById(R.id.search_src_text);
149aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood
1503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mSuggestionsView = (SuggestionsView) findViewById(R.id.suggestions);
151aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood        mSuggestionsView.setOnScrollListener(imeCloser);
152aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood        mSuggestionsView.setOnKeyListener(suggestionViewKeyListener);
15366ee1cc883f77fee930587503ecdcd8d18f12b23Mathew Inwood        mSuggestionsView.setOnFocusChangeListener(suggestionFocusListener);
1543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
155848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        mResultsView = (SuggestionsView) findViewById(R.id.shortcuts);
156d5cd9612d6937dfb174bfe6f4e486f283ef557e9Mathew Inwood        mSeparateResults = mResultsView != null;
157848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
158d5cd9612d6937dfb174bfe6f4e486f283ef557e9Mathew Inwood        if (mSeparateResults) {
159848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mSuggestionsAdapter = getQsbApplication().createSuggestionsAdapter();
160848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mResultsAdapter = getQsbApplication().createSuggestionsAdapter();
161848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mResultsAdapter.setSuggestionClickListener(new ClickHandler(mResultsAdapter));
162848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mResultsAdapter.setOnFocusChangeListener(suggestionFocusListener);
163aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            mResultsView.setOnScrollListener(imeCloser);
164aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            mResultsView.setOnFocusChangeListener(suggestionFocusListener);
165aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            mResultsView.setOnKeyListener(suggestionViewKeyListener);
166848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        } else {
167848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mSuggestionsAdapter = getQsbApplication().createSuggestionsAdapter();
168848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
169848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        mSuggestionsAdapter.setSuggestionClickListener(new ClickHandler(mSuggestionsAdapter));
170848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        mSuggestionsAdapter.setOnFocusChangeListener(suggestionFocusListener);
171848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
1723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mSearchGoButton = (ImageButton) findViewById(R.id.search_go_btn);
1733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mVoiceSearchButton = (ImageButton) findViewById(R.id.search_voice_btn);
17436cdac7349a76aa1db70ed7e8fa554ed54ad639dBjorn Bringert        mCorpusIndicator = (ImageButton) findViewById(R.id.corpus_indicator);
175848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        mSettingsButton = (ImageView) findViewById(R.id.settings_icon);
1763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
177782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        mQueryTextView.addTextChangedListener(new SearchTextWatcher());
178782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        mQueryTextView.setOnKeyListener(new QueryTextViewKeyListener());
1797b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert        mQueryTextView.setOnFocusChangeListener(new QueryTextViewFocusListener());
180848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        mQueryTextView.setSuggestionClickListener(new ClickHandler(mSuggestionsAdapter));
1812dfefcf67c7c28c8337725ef30d623a47638b374Mathew Inwood        mQueryTextEmptyBg = mQueryTextView.getBackground();
182782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
183848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        if (mCorpusIndicator != null) {
184848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mCorpusIndicator.setOnClickListener(new CorpusIndicatorClickListener());
185848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
1862617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
187782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        mSearchGoButton.setOnClickListener(new SearchGoButtonClickListener());
188782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
189782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        mVoiceSearchButton.setOnClickListener(new VoiceSearchButtonClickListener());
1907be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert
191848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        if (mSettingsButton != null) {
192848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mSettingsButton.setOnClickListener(new SettingsButtonClickListener());
193848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
194848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
1957be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        ButtonsKeyListener buttonsKeyListener = new ButtonsKeyListener();
1967be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        mSearchGoButton.setOnKeyListener(buttonsKeyListener);
1977be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        mVoiceSearchButton.setOnKeyListener(buttonsKeyListener);
198848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        if (mCorpusIndicator != null) {
199848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mCorpusIndicator.setOnKeyListener(buttonsKeyListener);
200848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
201713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
2029ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        mUpdateSuggestions = true;
2039ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
2049ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // First get setup from intent
2059ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        Intent intent = getIntent();
2069ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        setupFromIntent(intent);
2079ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // Then restore any saved instance state
2089ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        restoreInstanceState(savedInstanceState);
2099ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
210014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        mSuggestionsAdapter.registerDataSetObserver(new SuggestionsObserver());
211014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert
212713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        // Do this at the end, to avoid updating the list view when setSource()
213713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        // is called.
214713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        mSuggestionsView.setAdapter(mSuggestionsAdapter);
21521bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert
216d5cd9612d6937dfb174bfe6f4e486f283ef557e9Mathew Inwood        if (mSeparateResults) {
217848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mResultsAdapter.registerDataSetObserver(new SuggestionsObserver());
218848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mResultsView.setAdapter(mResultsAdapter);
219848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
22021bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        mCorporaObserver = new CorporaObserver();
22121bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        getCorpora().registerDataSetObserver(mCorporaObserver);
2229ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    }
223713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
2246ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert    protected void setContentView() {
2256ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert        setContentView(R.layout.search_activity);
2266ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert    }
2276ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert
22811234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert    private void startMethodTracing() {
22911234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        File traceDir = getDir("traces", 0);
23011234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        String traceFile = new File(traceDir, "qsb.trace").getAbsolutePath();
23111234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        Debug.startMethodTracing(traceFile);
23211234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert    }
23311234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert
2349ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    @Override
2359ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    protected void onNewIntent(Intent intent) {
236839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        if (DBG) Log.d(TAG, "onNewIntent()");
237ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        recordStartTime();
2389ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        setIntent(intent);
2399ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        setupFromIntent(intent);
2409ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    }
2419ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
242ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private void recordStartTime() {
243f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        mStartLatencyTracker = new LatencyTracker();
244ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mStarting = true;
245ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mTookAction = false;
246ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    }
247ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
2489ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    protected void restoreInstanceState(Bundle savedInstanceState) {
2499ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        if (savedInstanceState == null) return;
250fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        String corpusName = savedInstanceState.getString(INSTANCE_KEY_CORPUS);
251839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        String query = savedInstanceState.getString(INSTANCE_KEY_QUERY);
25221bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        setCorpus(corpusName);
253839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        setQuery(query, false);
254713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    }
255713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
256713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    @Override
2579ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    protected void onSaveInstanceState(Bundle outState) {
2589ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        super.onSaveInstanceState(outState);
2599ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // We don't save appSearchData, since we always get the value
2609ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // from the intent and the user can't change it.
261fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
26221bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        outState.putString(INSTANCE_KEY_CORPUS, getCorpusName());
263839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        outState.putString(INSTANCE_KEY_QUERY, getQuery());
264713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    }
265713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
266713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    private void setupFromIntent(Intent intent) {
267713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        if (DBG) Log.d(TAG, "setupFromIntent(" + intent.toUri(0) + ")");
26821bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        String corpusName = getCorpusNameFromUri(intent.getData());
2692617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        String query = intent.getStringExtra(SearchManager.QUERY);
2702617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        Bundle appSearchData = intent.getBundleExtra(SearchManager.APP_DATA);
271839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        boolean selectAll = intent.getBooleanExtra(SearchManager.EXTRA_SELECT_QUERY, false);
2722617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
27321bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        setCorpus(corpusName);
274839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        setQuery(query, selectAll);
275c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        mAppSearchData = appSearchData;
2762617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
27711c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert        if (startedIntoCorpusSelectionDialog()) {
27841fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert            showCorpusSelectionDialog();
2792617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        }
2809ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    }
2819ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
28211c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert    public boolean startedIntoCorpusSelectionDialog() {
28311c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert        return INTENT_ACTION_QSB_AND_SELECT_CORPUS.equals(getIntent().getAction());
28411c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert    }
28511c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert
286dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    /**
287dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert     * Removes corpus selector intent action, so that BACK works normally after
288dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert     * dismissing and reopening the corpus selector.
289dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert     */
290dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    private void clearStartedIntoCorpusSelectionDialog() {
291dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        Intent oldIntent = getIntent();
292dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        if (SearchActivity.INTENT_ACTION_QSB_AND_SELECT_CORPUS.equals(oldIntent.getAction())) {
293dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            Intent newIntent = new Intent(oldIntent);
294dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            newIntent.setAction(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
295dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            setIntent(newIntent);
296dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        }
297dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    }
298dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert
299fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public static Uri getCorpusUri(Corpus corpus) {
300fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (corpus == null) return null;
301fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return new Uri.Builder()
302fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                .scheme(SCHEME_CORPUS)
303fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                .authority(corpus.getName())
304fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                .build();
305fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
306fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
30721bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    private String getCorpusNameFromUri(Uri uri) {
308fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (uri == null) return null;
309fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (!SCHEME_CORPUS.equals(uri.getScheme())) return null;
31021bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        return uri.getAuthority();
311fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
312fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
313fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private Corpus getCorpus(String sourceName) {
3140ccab5903ba2c64ec4cdd33dbcea91b1e279d556Bjorn Bringert        if (sourceName == null) return null;
315fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        Corpus corpus = getCorpora().getCorpus(sourceName);
316fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (corpus == null) {
317fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            Log.w(TAG, "Unknown corpus " + sourceName);
3189ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert            return null;
319713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        }
320fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return corpus;
321713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    }
322713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
32321bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    private void setCorpus(String corpusName) {
32421bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        if (DBG) Log.d(TAG, "setCorpus(" + corpusName + ")");
32521bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        mCorpus = getCorpus(corpusName);
3269ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        Drawable sourceIcon;
32721bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        if (mCorpus == null) {
32836cdac7349a76aa1db70ed7e8fa554ed54ad639dBjorn Bringert            sourceIcon = getCorpusViewFactory().getGlobalSearchIcon();
329713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        } else {
33021bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert            sourceIcon = mCorpus.getCorpusIcon();
331713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        }
33221bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        mSuggestionsAdapter.setCorpus(mCorpus);
333aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood        if (mResultsAdapter != null) {
334aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            mResultsAdapter.setCorpus(mCorpus);
335aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood        }
336848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        if (mCorpusIndicator != null) {
337848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mCorpusIndicator.setImageDrawable(sourceIcon);
338848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
3393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
3405691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert        updateUi(getQuery().length() == 0);
3410484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    }
3420484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
34321bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    private String getCorpusName() {
34421bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        return mCorpus == null ? null : mCorpus.getName();
34521bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    }
34621bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert
3473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private QsbApplication getQsbApplication() {
34849fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        return QsbApplication.get(this);
3493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
351848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected boolean separateResults() {
352d5cd9612d6937dfb174bfe6f4e486f283ef557e9Mathew Inwood        return mSeparateResults;
353848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
354848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
3554ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    private Config getConfig() {
3564ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert        return getQsbApplication().getConfig();
3574ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    }
3584ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert
359d5cd9612d6937dfb174bfe6f4e486f283ef557e9Mathew Inwood    public Corpora getCorpora() {
360d5cd9612d6937dfb174bfe6f4e486f283ef557e9Mathew Inwood        return separateResults() ? getQsbApplication().getResultsCorpora()
361d5cd9612d6937dfb174bfe6f4e486f283ef557e9Mathew Inwood                                 : getQsbApplication().getAllCorpora();
362fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
363fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
3643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private ShortcutRepository getShortcutRepository() {
365d5cd9612d6937dfb174bfe6f4e486f283ef557e9Mathew Inwood        return getQsbApplication().getShortcutRepository(getCorpora());
3663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
368ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private SuggestionsProvider getSuggestionsProvider() {
369848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        return separateResults() ? getQsbApplication().getWebSuggestionsProvider()
370848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani                                : getQsbApplication().getUnifiedProvider();
371848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
372848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
373848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    private SuggestionsProvider getResultsProvider() {
374848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        return getQsbApplication().getResultsProvider();
37547d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert    }
37647d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert
377c5a3ecb62318a6be1d1a626a36b52829e989f740Bjorn Bringert    private CorpusViewFactory getCorpusViewFactory() {
378c5a3ecb62318a6be1d1a626a36b52829e989f740Bjorn Bringert        return getQsbApplication().getCorpusViewFactory();
379185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert    }
380185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
38149fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    private VoiceSearch getVoiceSearch() {
38249fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        return QsbApplication.get(this).getVoiceSearch();
38349fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    }
38449fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert
385ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private Logger getLogger() {
386ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        return getQsbApplication().getLogger();
387ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    }
388ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
3893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
3903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void onDestroy() {
3913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "onDestroy()");
3923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        super.onDestroy();
39321bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        getCorpora().unregisterDataSetObserver(mCorporaObserver);
394185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert        mSuggestionsView.setAdapter(null);  // closes mSuggestionsAdapter
395aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood        if (mResultsView != null) {
396848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mResultsView.setAdapter(null);
397848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
3983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
4003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
4013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void onStop() {
4029ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        if (DBG) Log.d(TAG, "onStop()");
403f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        if (!mTookAction) {
404848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            // TODO: This gets logged when starting other activities, e.g. by opening the search
405f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            // settings, or clicking a notification in the status bar.
406aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            // TODO we should log both sets of suggestions in 2-pane mode
407f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            getLogger().logExit(getCurrentSuggestions(), getQuery().length());
408f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        }
4099ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // Close all open suggestion cursors. The query will be redone in onResume()
4103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        // if we come back to this activity.
411185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert        mSuggestionsAdapter.setSuggestions(null);
412848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        if (mResultsAdapter != null) {
413848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mResultsAdapter.setSuggestions(null);
414848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
41594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney        getQsbApplication().getShortcutRefresher().reset();
416f69873ae02e6d8f8a550f5fa43b5b1f2cbea96ffBjorn Bringert        dismissCorpusSelectionDialog();
4173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        super.onStop();
4183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
4193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
4203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
421839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert    protected void onRestart() {
422839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        if (DBG) Log.d(TAG, "onRestart()");
423839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        super.onRestart();
424839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert    }
425839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert
426839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert    @Override
427b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert    protected void onResume() {
4289ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        if (DBG) Log.d(TAG, "onResume()");
429b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert        super.onResume();
43011234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        updateSuggestionsBuffered();
431dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        if (!isCorpusSelectionDialogShowing()) {
432dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            mQueryTextView.requestFocus();
433dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        }
43411234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        if (TRACE) Debug.stopMethodTracing();
435b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert    }
436b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert
437b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert    @Override
4383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public boolean onCreateOptionsMenu(Menu menu) {
4393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        super.onCreateOptionsMenu(menu);
44026d85260316193a1aeff5d407d4f32f5297be012Bjorn Bringert        SearchSettings.addSearchSettingsMenuItem(this, menu);
4413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return true;
4423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
4433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
444d98911178013162737fbba74387b51d2a08b0493Amith Yamasani    @Override
445d98911178013162737fbba74387b51d2a08b0493Amith Yamasani    public void onWindowFocusChanged(boolean hasFocus) {
446d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        super.onWindowFocusChanged(hasFocus);
447d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        if (hasFocus) {
448d98911178013162737fbba74387b51d2a08b0493Amith Yamasani            // Launch the IME after a bit
449d98911178013162737fbba74387b51d2a08b0493Amith Yamasani            mHandler.postDelayed(mShowInputMethodTask, 0);
450d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        }
451d98911178013162737fbba74387b51d2a08b0493Amith Yamasani    }
452d98911178013162737fbba74387b51d2a08b0493Amith Yamasani
453713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    protected String getQuery() {
4543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        CharSequence q = mQueryTextView.getText();
4553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return q == null ? "" : q.toString();
4563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
4573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
4583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
459014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert     * Sets the text in the query box. Does not update the suggestions.
4603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
4613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private void setQuery(String query, boolean selectAll) {
4623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mUpdateSuggestions = false;
4633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mQueryTextView.setText(query);
464014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        mQueryTextView.setTextSelection(selectAll);
4653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mUpdateSuggestions = true;
4663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
4673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
46818959800eddb7127e4fd9b24e91458d0584cc257Mathew Inwood    protected void updateUi(boolean queryEmpty) {
4695691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert        updateQueryTextView(queryEmpty);
4705691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert        updateSearchGoButton(queryEmpty);
4715691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert        updateVoiceSearchButton(queryEmpty);
4725691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert    }
4735691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert
474e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    private void updateQueryTextView(boolean queryEmpty) {
475e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        if (queryEmpty) {
47620c51f89fdba5105efdf0a37f50bf7fa013d5b8dMathew Inwood            if (isSearchCorpusWeb()) {
4772dfefcf67c7c28c8337725ef30d623a47638b374Mathew Inwood                mQueryTextView.setBackgroundDrawable(mQueryTextEmptyBg);
4785691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert                mQueryTextView.setHint(null);
4795691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert            } else {
4802dfefcf67c7c28c8337725ef30d623a47638b374Mathew Inwood                if (mQueryTextNotEmptyBg == null) {
4812dfefcf67c7c28c8337725ef30d623a47638b374Mathew Inwood                    mQueryTextNotEmptyBg =
4822dfefcf67c7c28c8337725ef30d623a47638b374Mathew Inwood                            getResources().getDrawable(R.drawable.textfield_search_empty);
4832dfefcf67c7c28c8337725ef30d623a47638b374Mathew Inwood                }
4842dfefcf67c7c28c8337725ef30d623a47638b374Mathew Inwood                mQueryTextView.setBackgroundDrawable(mQueryTextNotEmptyBg);
4855691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert                mQueryTextView.setHint(mCorpus.getHint());
4865691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert            }
487e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        } else {
488e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            mQueryTextView.setBackgroundResource(R.drawable.textfield_search);
489e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        }
490e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    }
491e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert
492e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    private void updateSearchGoButton(boolean queryEmpty) {
493e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        if (queryEmpty) {
494e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            mSearchGoButton.setVisibility(View.GONE);
495e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        } else {
496e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            mSearchGoButton.setVisibility(View.VISIBLE);
497e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        }
498e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    }
499e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert
500e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    protected void updateVoiceSearchButton(boolean queryEmpty) {
50149fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        if (queryEmpty && getVoiceSearch().shouldShowVoiceSearch(mCorpus)) {
502e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            mVoiceSearchButton.setVisibility(View.VISIBLE);
503e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            mQueryTextView.setPrivateImeOptions(IME_OPTION_NO_MICROPHONE);
504e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        } else {
505e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            mVoiceSearchButton.setVisibility(View.GONE);
506e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            mQueryTextView.setPrivateImeOptions(null);
507e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert        }
508e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    }
509e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert
51041fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert    protected void showCorpusSelectionDialog() {
511f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        if (mCorpusSelectionDialog == null) {
51223db3f9877e691568fe2c955fd9d4f48a2eb937aMathew Inwood            mCorpusSelectionDialog = createCorpusSelectionDialog();
513f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            mCorpusSelectionDialog.setOwnerActivity(this);
514dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            mCorpusSelectionDialog.setOnDismissListener(new CorpusSelectorDismissListener());
515f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            mCorpusSelectionDialog.setOnCorpusSelectedListener(new CorpusSelectionListener());
5162617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        }
517f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        mCorpusSelectionDialog.show(mCorpus);
5182617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert    }
5192617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
52023db3f9877e691568fe2c955fd9d4f48a2eb937aMathew Inwood    protected CorpusSelectionDialog createCorpusSelectionDialog() {
52135c43805a450c17d5fc5e27dc073edc6e2cd7320Amith Yamasani        return new CorpusSelectionDialog(this);
52235c43805a450c17d5fc5e27dc073edc6e2cd7320Amith Yamasani    }
52335c43805a450c17d5fc5e27dc073edc6e2cd7320Amith Yamasani
524dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    protected boolean isCorpusSelectionDialogShowing() {
525dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        return mCorpusSelectionDialog != null && mCorpusSelectionDialog.isShowing();
526dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    }
527dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert
528f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    protected void dismissCorpusSelectionDialog() {
529f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        if (mCorpusSelectionDialog != null) {
530f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            mCorpusSelectionDialog.dismiss();
5312617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        }
5322617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert    }
5332617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
534dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood    /**
535dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood     * @return true if a search was performed as a result of this click, false otherwise.
536dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood     */
537dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood    protected boolean onSearchClicked(int method) {
5383a7125b39b72f7417684c4d3040abeb4a81bd6b3Bjorn Bringert        String query = CharMatcher.WHITESPACE.trimAndCollapseFrom(getQuery(), ' ');
5393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "Search clicked, query=" + query);
540eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert
541eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert        // Don't do empty queries
542dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood        if (TextUtils.getTrimmedLength(query) == 0) return false;
543eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert
54481a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        Corpus searchCorpus = getSearchCorpus();
545dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood        if (searchCorpus == null) return false;
546c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
547ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mTookAction = true;
548c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
549c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Log search start
550fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        getLogger().logSearch(mCorpus, method, query.length());
551c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
552c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Create shortcut
553c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        SuggestionData searchShortcut = searchCorpus.createSearchShortcut(query);
554c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        if (searchShortcut != null) {
55593bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert            ListSuggestionCursor cursor = new ListSuggestionCursor(query);
556c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert            cursor.add(searchShortcut);
557c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert            getShortcutRepository().reportClick(cursor, 0);
558c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        }
559c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
560c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Start search
561c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        Intent intent = searchCorpus.createSearchIntent(query, mAppSearchData);
56281a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        launchIntent(intent);
563dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood        return true;
5643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
5653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
5663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void onVoiceSearchClicked() {
5673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "Voice Search clicked");
56881a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        Corpus searchCorpus = getSearchCorpus();
569c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        if (searchCorpus == null) return;
570c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
571535931433926d342c6277034cad91143ae28b72dBjorn Bringert        mTookAction = true;
572535931433926d342c6277034cad91143ae28b72dBjorn Bringert
573c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Log voice search start
574c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        getLogger().logVoiceSearch(searchCorpus);
575ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
576c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Start voice search
577c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        Intent intent = searchCorpus.createVoiceSearchIntent(mAppSearchData);
57881a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        launchIntent(intent);
57981a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert    }
58081a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert
581848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected void onSettingsClicked() {
582848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        SearchSettings.launchSettings(this);
583848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
584848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
58581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert    /**
58681a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert     * Gets the corpus to use for any searches. This is the web corpus in "All" mode,
58781a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert     * and the selected corpus otherwise.
58881a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert     */
589ca9c7b7bc0183aa1b6d160bf76597c96e70831f6Mathew Inwood    protected Corpus getSearchCorpus() {
59081a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        if (mCorpus != null) {
59181a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            return mCorpus;
59281a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        } else {
59381a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            Corpus webCorpus = getCorpora().getWebCorpus();
59481a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            if (webCorpus == null) {
59581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert                Log.e(TAG, "No web corpus");
59681a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            }
59781a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            return webCorpus;
59881a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        }
599c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert    }
600c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
601014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert    /**
602d5cd9612d6937dfb174bfe6f4e486f283ef557e9Mathew Inwood     * Checks if the corpus used for typed searches is the web corpus.
603014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert     */
604014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert    protected boolean isSearchCorpusWeb() {
605014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        Corpus corpus = getSearchCorpus();
606014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        return corpus != null && corpus.isWebCorpus();
607014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert    }
608014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert
609aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood    @Deprecated
610e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringert    protected SuggestionCursor getCurrentSuggestions() {
611fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return mSuggestionsAdapter.getCurrentSuggestions();
612782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    }
613782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
614848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected SuggestionCursor getCurrentSuggestions(SuggestionsAdapter adapter, int position) {
615848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        SuggestionCursor suggestions = adapter.getCurrentSuggestions();
6165f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (suggestions == null) {
6175f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert            return null;
6185f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        }
6195f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        int count = suggestions.getCount();
6205f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (position < 0 || position >= count) {
6215f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert            Log.w(TAG, "Invalid suggestion position " + position + ", count = " + count);
6225f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert            return null;
6235f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        }
6245f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        suggestions.moveTo(position);
6255f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        return suggestions;
6265f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert    }
6275f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert
628848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    private BlendedSuggestions blendedOrNothing(Suggestions s) {
629848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        if (s instanceof BlendedSuggestions) return (BlendedSuggestions) s;
630848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        return null;
631848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
632848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
633848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    private BlendedSuggestions pickBlended(Suggestions... suggestionses) {
634848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        for (Suggestions s : suggestionses) {
635848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            BlendedSuggestions b = blendedOrNothing(s);
636848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            if (b != null) return b;
637848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
638848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        return null;
639848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
640848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
641848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    private BlendedSuggestions getBlendedSuggestions() {
642848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        return pickBlended(
643848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani                mResultsAdapter == null ? null : mResultsAdapter.getSuggestions(),
644848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani                mSuggestionsAdapter.getSuggestions());
645848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
646848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
6475f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert    protected Set<Corpus> getCurrentIncludedCorpora() {
648848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        BlendedSuggestions suggestions = getBlendedSuggestions();
649848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        return suggestions == null  ? null : suggestions.getIncludedCorpora();
6505f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert    }
6515f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert
65281a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert    protected void launchIntent(Intent intent) {
65381a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        if (intent == null) {
65481a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            return;
65581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        }
65681a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        try {
65781a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            startActivity(intent);
65881a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        } catch (RuntimeException ex) {
65981a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            // Since the intents for suggestions specified by suggestion providers,
66081a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            // guard against them not being handled, not allowed, etc.
66181a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            Log.e(TAG, "Failed to start " + intent.toUri(0), ex);
66281a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        }
66381a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert    }
66481a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert
665848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected boolean launchSuggestion(SuggestionsAdapter adapter, int position) {
666848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        SuggestionCursor suggestions = getCurrentSuggestions(adapter, position);
667848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        // SuggestionCursor suggestions = new
668848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        // ListSuggestionCursor(adapter.getCurrentSuggestions()
669848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        // .getUserQuery());
670848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        // suggestions.add(new SuggestionPosition(adapter.getItem(position),
671848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        // 0));
6725f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (suggestions == null) return false;
6736f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert
674fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (DBG) Log.d(TAG, "Launching suggestion " + position);
675ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mTookAction = true;
676e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringert
677c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Log suggestion click
678c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        getLogger().logSuggestionClick(position, suggestions, getCurrentIncludedCorpora(),
679c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert                Logger.SUGGESTION_CLICK_TYPE_LAUNCH);
680ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
681c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Create shortcut
682fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        getShortcutRepository().reportClick(suggestions, position);
683c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
684c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Launch intent
68581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        suggestions.moveTo(position);
68693bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert        Intent intent = SuggestionUtils.getSuggestionIntent(suggestions, mAppSearchData);
68781a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        launchIntent(intent);
688c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
6893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return true;
6903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
6913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
692aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood    protected void clickedQuickContact(SuggestionsAdapter adapter, int position) {
693aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood        SuggestionCursor suggestions = getCurrentSuggestions(adapter, position);
694c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        if (suggestions == null) return;
695c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert
696c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        if (DBG) Log.d(TAG, "Used suggestion " + position);
697c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        mTookAction = true;
698c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert
699c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        // Log suggestion click
700c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        getLogger().logSuggestionClick(position, suggestions, getCurrentIncludedCorpora(),
701c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert                Logger.SUGGESTION_CLICK_TYPE_QUICK_CONTACT);
702c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert
703c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        // Create shortcut
704c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        getShortcutRepository().reportClick(suggestions, position);
705c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert    }
706c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert
707848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected boolean onSuggestionLongClicked(SuggestionsAdapter adapter, int position) {
708fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (DBG) Log.d(TAG, "Long clicked on suggestion " + position);
7093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return false;
7103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
7113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
712aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood    protected boolean onSuggestionKeyDown(SuggestionsAdapter adapter,
713aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            int position, int keyCode, KeyEvent event) {
714782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        // Treat enter or search as a click
715a20a61d8141129e8734df8e953c7b311e72dd144Mathew Inwood        if (       keyCode == KeyEvent.KEYCODE_ENTER
716a20a61d8141129e8734df8e953c7b311e72dd144Mathew Inwood                || keyCode == KeyEvent.KEYCODE_SEARCH
717a20a61d8141129e8734df8e953c7b311e72dd144Mathew Inwood                || keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
718aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            return launchSuggestion(adapter, position);
719782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        }
720782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
721782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        return false;
722782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    }
723782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
724848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected void refineSuggestion(SuggestionsAdapter adapter, int position) {
7255f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (DBG) Log.d(TAG, "query refine clicked, pos " + position);
726848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        SuggestionCursor suggestions = getCurrentSuggestions(adapter, position);
7275f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (suggestions == null) {
7285f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert            return;
7295f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        }
7305f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        String query = suggestions.getSuggestionQuery();
7315f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (TextUtils.isEmpty(query)) {
7325f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert            return;
7335f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        }
7345f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert
7355f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        // Log refine click
736c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        getLogger().logSuggestionClick(position, suggestions, getCurrentIncludedCorpora(),
737c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert                Logger.SUGGESTION_CLICK_TYPE_REFINE);
7385f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert
7395f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        // Put query + space in query text view
7405f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        String queryWithSpace = query + ' ';
7415f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        setQuery(queryWithSpace, false);
7425f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        updateSuggestions(queryWithSpace);
7435f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        mQueryTextView.requestFocus();
7445f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert    }
7455f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert
7463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
7473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Hides the input method.
7483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
749aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood    protected void considerHidingInputMethod() {
750aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood        if (getConfig().isKeyboardDismissedOnScroll()) {
751aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            mQueryTextView.hideInputMethod();
752aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood        }
7533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
7543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
7557b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert    protected void showInputMethodForQuery() {
756014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        mQueryTextView.showInputMethod();
7577b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert    }
7587b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert
759aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood    protected void onSuggestionListFocusChange(SuggestionsView suggestions, boolean focused) {
760f5e1499b48ac06de4e6e6460a7f14c3a7ac4eaddMathew Inwood    }
761f5e1499b48ac06de4e6e6460a7f14c3a7ac4eaddMathew Inwood
762f5e1499b48ac06de4e6e6460a7f14c3a7ac4eaddMathew Inwood    protected void onQueryTextViewFocusChange(boolean focused) {
763f5e1499b48ac06de4e6e6460a7f14c3a7ac4eaddMathew Inwood    }
764f5e1499b48ac06de4e6e6460a7f14c3a7ac4eaddMathew Inwood
7653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
7663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Hides the input method when the suggestions get focus.
7673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
7683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private class SuggestListFocusListener implements OnFocusChangeListener {
7693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        public void onFocusChange(View v, boolean focused) {
7707b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            if (DBG) Log.d(TAG, "Suggestions focus change, now: " + focused);
771aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            if (focused && v instanceof SuggestionsView) {
772aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood                SuggestionsView view = (SuggestionsView) v;
773aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood                considerHidingInputMethod();
774aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood                onSuggestionListFocusChange(view, focused);
7757b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            }
7767b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert        }
7777b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert    }
7787b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert
7797b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert    private class QueryTextViewFocusListener implements OnFocusChangeListener {
7807b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert        public void onFocusChange(View v, boolean focused) {
7817b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            if (DBG) Log.d(TAG, "Query focus change, now: " + focused);
7827b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert            if (focused) {
783dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert                // The query box got focus, show the input method
7847b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert                showInputMethodForQuery();
7853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            }
786f5e1499b48ac06de4e6e6460a7f14c3a7ac4eaddMathew Inwood            onQueryTextViewFocusChange(focused);
7873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
7883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
7893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
790e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney    private int getMaxSuggestions() {
791e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney        Config config = getConfig();
792e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney        return mCorpus == null
793e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney                ? config.getMaxPromotedSuggestions()
794e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney                : config.getMaxResultsPerSource();
795e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney    }
796e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney
7974ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    private void updateSuggestionsBuffered() {
798d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        mHandler.removeCallbacks(mUpdateSuggestionsTask);
7994ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert        long delay = getConfig().getTypingUpdateSuggestionsDelayMillis();
800d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        mHandler.postDelayed(mUpdateSuggestionsTask, delay);
8014ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    }
8024ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert
803848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    private void gotSuggestions(BlendedSuggestions suggestions) {
80411234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        if (mStarting) {
80511234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert            mStarting = false;
80611234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert            String source = getIntent().getStringExtra(Search.SOURCE);
80711234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert            int latency = mStartLatencyTracker.getLatency();
808848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            getLogger().logStart(latency, source, mCorpus,
809848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani                    suggestions == null ? null : suggestions.getExpectedCorpora());
810b5560dbe16a8fb3148b0fb24c73836bf2e84dd61Mathew Inwood            getQsbApplication().onStartupComplete();
81111234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        }
812848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
813848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
814848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected void updateSuggestions(String query) {
81511234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert
816848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        query = CharMatcher.WHITESPACE.trimLeadingFrom(query);
817848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        if (DBG) Log.d(TAG, "getSuggestions(\""+query+"\","+mCorpus + ","+getMaxSuggestions()+")");
818848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        if (!separateResults()) {
819848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            Suggestions suggestions = getSuggestionsProvider().getSuggestions(
820848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani                    query, mCorpus, getMaxSuggestions());
821848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            // Log start latency if this is the first suggestions update
822848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            gotSuggestions(blendedOrNothing(suggestions));
823848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mSuggestionsAdapter.setSuggestions(suggestions);
824848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        } else {
825848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            // TODO getMaxSuggestions() - different for suggestions & results?
826848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            Suggestions webSuggestions = getSuggestionsProvider().getSuggestions(
827848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani                    query, null, getMaxSuggestions());
828848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            Suggestions results = getResultsProvider().getSuggestions(
829848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani                    query, mCorpus, getMaxSuggestions());
830848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            // TODO gotSuggestions(webSuggestions, results)
831848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            gotSuggestions(pickBlended(results, webSuggestions));
832d5cd9612d6937dfb174bfe6f4e486f283ef557e9Mathew Inwood
833848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mSuggestionsAdapter.setSuggestions(webSuggestions);
834848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mResultsAdapter.setSuggestions(results);
835848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
8363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
8373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
838014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert    /**
839014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert     * If the input method is in fullscreen mode, and the selector corpus
840014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert     * is All or Web, use the web search suggestions as completions.
841014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert     */
842014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert    protected void updateInputMethodSuggestions() {
843014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
844014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        if (imm == null || !imm.isFullscreenMode()) return;
845014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        Suggestions suggestions = mSuggestionsAdapter.getSuggestions();
846014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        if (suggestions == null) return;
847014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        SuggestionCursor cursor = suggestions.getPromoted();
848014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        if (cursor == null) return;
849014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        CompletionInfo[] completions = webSuggestionsToCompletions(cursor);
850014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        if (DBG) Log.d(TAG, "displayCompletions(" + Arrays.toString(completions) + ")");
851014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        imm.displayCompletions(mQueryTextView, completions);
852014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert    }
853014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert
854014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert    private CompletionInfo[] webSuggestionsToCompletions(SuggestionCursor cursor) {
855014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        int count = cursor.getCount();
856014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        ArrayList<CompletionInfo> completions = new ArrayList<CompletionInfo>(count);
85720c51f89fdba5105efdf0a37f50bf7fa013d5b8dMathew Inwood        boolean usingWebCorpus = isSearchCorpusWeb();
858014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        for (int i = 0; i < count; i++) {
859014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert            cursor.moveTo(i);
86020c51f89fdba5105efdf0a37f50bf7fa013d5b8dMathew Inwood            if (!usingWebCorpus || cursor.isWebSearchSuggestion()) {
861014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert                String text1 = cursor.getSuggestionText1();
862014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert                completions.add(new CompletionInfo(i, i, text1));
863014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert            }
864014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        }
865014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        return completions.toArray(new CompletionInfo[completions.size()]);
866014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert    }
867014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert
8687be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert    private boolean forwardKeyToQueryTextView(int keyCode, KeyEvent event) {
8697be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        if (!event.isSystem() && !isDpadKey(keyCode)) {
8707be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            if (DBG) Log.d(TAG, "Forwarding key to query box: " + event);
8717be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            if (mQueryTextView.requestFocus()) {
8727be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert                return mQueryTextView.dispatchKeyEvent(event);
8737be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            }
8747be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        }
8757be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        return false;
8767be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert    }
8777be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert
8787be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert    private boolean isDpadKey(int keyCode) {
8797be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        switch (keyCode) {
8807be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            case KeyEvent.KEYCODE_DPAD_UP:
8817be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            case KeyEvent.KEYCODE_DPAD_DOWN:
8827be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            case KeyEvent.KEYCODE_DPAD_LEFT:
8837be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            case KeyEvent.KEYCODE_DPAD_RIGHT:
8847be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            case KeyEvent.KEYCODE_DPAD_CENTER:
8857be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert                return true;
8867be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            default:
8877be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert                return false;
8887be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert        }
8897be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert    }
8907be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert
8913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
8923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Filters the suggestions list when the search text changes.
8933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
8943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private class SearchTextWatcher implements TextWatcher {
8953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        public void afterTextChanged(Editable s) {
896e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            boolean empty = s.length() == 0;
897e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            if (empty != mQueryWasEmpty) {
898e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert                mQueryWasEmpty = empty;
8995691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert                updateUi(empty);
900e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert            }
9013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            if (mUpdateSuggestions) {
9024ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert                updateSuggestionsBuffered();
9033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            }
9043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
9053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
9063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
9073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
9083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
9093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        public void onTextChanged(CharSequence s, int start, int before, int count) {
9103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
9113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
9123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
9133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
9143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Handles non-text keys in the query text view.
9153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
9163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private class QueryTextViewKeyListener implements View.OnKeyListener {
9173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        public boolean onKey(View view, int keyCode, KeyEvent event) {
9183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            // Handle IME search action key
9193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) {
920d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood                // if no action was taken, consume the key event so that the keyboard
921d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood                // remains on screen.
922dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood                return !onSearchClicked(Logger.SEARCH_METHOD_KEYBOARD);
9233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            }
9243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            return false;
9253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
9263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
9273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
928782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    /**
929782dd228e78e9294692d639597f96c26283968bbBjorn Bringert     * Handles key events on the search and voice search buttons,
930782dd228e78e9294692d639597f96c26283968bbBjorn Bringert     * by refocusing to EditText.
931782dd228e78e9294692d639597f96c26283968bbBjorn Bringert     */
932782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    private class ButtonsKeyListener implements View.OnKeyListener {
933782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        public boolean onKey(View v, int keyCode, KeyEvent event) {
9347be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            return forwardKeyToQueryTextView(keyCode, event);
935782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        }
936782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    }
937782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
938782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    /**
939782dd228e78e9294692d639597f96c26283968bbBjorn Bringert     * Handles key events on the suggestions list view.
940782dd228e78e9294692d639597f96c26283968bbBjorn Bringert     */
941713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    private class SuggestionsViewKeyListener implements View.OnKeyListener {
942782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        public boolean onKey(View v, int keyCode, KeyEvent event) {
943aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            if (event.getAction() == KeyEvent.ACTION_DOWN
944aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood                    && v instanceof SuggestionsView) {
945aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood                SuggestionsView view = ((SuggestionsView) v);
946aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood                int position = view.getSelectedPosition();
947aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood                if (onSuggestionKeyDown(view.getAdapter(), position, keyCode, event)) {
948839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert                    return true;
949782dd228e78e9294692d639597f96c26283968bbBjorn Bringert                }
950782dd228e78e9294692d639597f96c26283968bbBjorn Bringert            }
9517be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert            return forwardKeyToQueryTextView(keyCode, event);
952782dd228e78e9294692d639597f96c26283968bbBjorn Bringert        }
953782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    }
954782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
955145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert    private class InputMethodCloser implements SuggestionsView.OnScrollListener {
956145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert
957145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
958145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert                int totalItemCount) {
959145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert        }
960145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert
961145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert        public void onScrollStateChanged(AbsListView view, int scrollState) {
962aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            considerHidingInputMethod();
963185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert        }
964185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert    }
965185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
966185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert    private class ClickHandler implements SuggestionClickListener {
967aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood        private final SuggestionsAdapter mAdapter;
968848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
969848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        public ClickHandler(SuggestionsAdapter suggestionsAdapter) {
970aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            mAdapter = suggestionsAdapter;
971848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
972c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert
973848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        public void onSuggestionQuickContactClicked(int position) {
974aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            clickedQuickContact(mAdapter, position);
975848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
976848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
977848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        public void onSuggestionClicked(int position) {
978aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            launchSuggestion(mAdapter, position);
979848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
9803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
981848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        public boolean onSuggestionLongClicked(int position) {
982aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            return SearchActivity.this.onSuggestionLongClicked(mAdapter, position);
983848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
984145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert
985848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        public void onSuggestionQueryRefineClicked(int position) {
986aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            refineSuggestion(mAdapter, position);
987848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
9883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
9893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
9903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
9912617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert     * Listens for clicks on the source selector.
9923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
9933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private class SearchGoButtonClickListener implements View.OnClickListener {
9943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        public void onClick(View view) {
995ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert            onSearchClicked(Logger.SEARCH_METHOD_BUTTON);
9963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
9973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
9983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
9993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
10002617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert     * Listens for clicks on the search button.
10012617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert     */
1002fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private class CorpusIndicatorClickListener implements View.OnClickListener {
10032617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        public void onClick(View view) {
100441fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert            showCorpusSelectionDialog();
10052617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        }
1006f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    }
1007f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert
1008dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    private class CorpusSelectorDismissListener implements DialogInterface.OnDismissListener {
1009dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        public void onDismiss(DialogInterface dialog) {
1010dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            if (DBG) Log.d(TAG, "Corpus selector dismissed");
1011dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            clearStartedIntoCorpusSelectionDialog();
1012dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        }
1013dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    }
1014dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert
1015f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    private class CorpusSelectionListener
1016f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            implements CorpusSelectionDialog.OnCorpusSelectedListener {
101721bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        public void onCorpusSelected(String corpusName) {
101821bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert            setCorpus(corpusName);
1019f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            updateSuggestions(getQuery());
1020f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            mQueryTextView.requestFocus();
1021dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            showInputMethodForQuery();
1022f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        }
10232617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert    }
10242617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
10252617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert    /**
10263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Listens for clicks on the voice search button.
10273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
10283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private class VoiceSearchButtonClickListener implements View.OnClickListener {
10293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        public void onClick(View view) {
10303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            onVoiceSearchClicked();
10313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
10323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
10333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1034848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    /**
1035848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani     * Listens for clicks on the settings button.
1036848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani     */
1037848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    private class SettingsButtonClickListener implements View.OnClickListener {
1038848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        public void onClick(View view) {
1039848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            onSettingsClicked();
1040848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
1041848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
1042848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
104321bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    private class CorporaObserver extends DataSetObserver {
104421bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        @Override
104521bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        public void onChanged() {
104621bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert            setCorpus(getCorpusName());
104721bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert            updateSuggestions(getQuery());
104821bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        }
104921bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    }
105021bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert
1051014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert    private class SuggestionsObserver extends DataSetObserver {
1052014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        @Override
1053014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        public void onChanged() {
1054014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert            updateInputMethodSuggestions();
1055014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert        }
1056014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert    }
1057014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert
10583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert}
1059