SearchActivity.java revision e833f84eee7ab575c8d53dec9b133fa5de9c7e6d
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;
207010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringertimport com.android.quicksearchbox.ui.SearchActivityView;
21185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionClickListener;
22185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionsAdapter;
23b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringertimport com.android.quicksearchbox.util.Consumer;
24b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringertimport com.android.quicksearchbox.util.Consumers;
252607687d72deb8e06329597ab8bffcca9c746153Mathew Inwoodimport com.google.common.annotations.VisibleForTesting;
263a7125b39b72f7417684c4d3040abeb4a81bd6b3Bjorn Bringertimport com.google.common.base.CharMatcher;
27185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.app.Activity;
293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.app.SearchManager;
30dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringertimport android.content.DialogInterface;
313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.Intent;
3221bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringertimport android.database.DataSetObserver;
33fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.net.Uri;
343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.os.Bundle;
3511234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringertimport android.os.Debug;
364ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringertimport android.os.Handler;
373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.TextUtils;
383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.util.Log;
393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.Menu;
403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.View;
41fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringertimport android.widget.Toast;
423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
4311234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringertimport java.io.File;
44dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringertimport java.util.ArrayList;
454572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwoodimport java.util.Collection;
46b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringertimport java.util.List;
475f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringertimport java.util.Set;
48ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/**
503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * The main activity for Quick Search Box. Shows the search UI.
513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert *
523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */
533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpublic class SearchActivity extends Activity {
543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
55754cb6b769c5955fc707a6c5ab6689b64df102b3Mathew Inwood    private static final boolean DBG = false;
560484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    private static final String TAG = "QSB.SearchActivity";
5711234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert    private static final boolean TRACE = false;
583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
59fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private static final String SCHEME_CORPUS = "qsb.corpus";
60fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
61fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public static final String INTENT_ACTION_QSB_AND_SELECT_CORPUS
62fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            = "com.android.quicksearchbox.action.QSB_AND_SELECT_CORPUS";
633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
649ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    // Keys for the saved instance state.
65fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private static final String INSTANCE_KEY_CORPUS = "corpus";
66839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert    private static final String INSTANCE_KEY_QUERY = "query";
67713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
68f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    // Measures time from for last onCreate()/onNewIntent() call.
69f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    private LatencyTracker mStartLatencyTracker;
7098cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood    // Measures time spent inside onCreate()
7198cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood    private LatencyTracker mOnCreateTracker;
7298cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood    private int mOnCreateLatency;
73ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    // Whether QSB is starting. True between the calls to onCreate()/onNewIntent() and onResume().
74ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private boolean mStarting;
75ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    // True if the user has taken some action, e.g. launching a search, voice search,
76ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    // or suggestions, since QSB was last started.
77ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private boolean mTookAction;
78ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
797010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private SearchActivityView mSearchActivityView;
80185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
8121bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    private CorporaObserver mCorporaObserver;
8221bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert
832617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert    private Bundle mAppSearchData;
843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
85d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood    private final Handler mHandler = new Handler();
86d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood    private final Runnable mUpdateSuggestionsTask = new Runnable() {
874ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert        public void run() {
887f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert            updateSuggestions();
894ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert        }
904ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    };
914ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert
92d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood    private final Runnable mShowInputMethodTask = new Runnable() {
93d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        public void run() {
947010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            mSearchActivityView.showInputMethodForQuery();
95d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        }
96d98911178013162737fbba74387b51d2a08b0493Amith Yamasani    };
97d98911178013162737fbba74387b51d2a08b0493Amith Yamasani
982607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood    private OnDestroyListener mDestroyListener;
992607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood
1003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /** Called when the activity is first created. */
1013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
1023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public void onCreate(Bundle savedInstanceState) {
10311234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        if (TRACE) startMethodTracing();
104ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        recordStartTime();
1053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "onCreate()");
1063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        super.onCreate(savedInstanceState);
107713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
1085880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert        mSearchActivityView = setupContentView();
109aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood
110fdb80c2962c88ac62dcd7ee7f2fab1857b61506bMathew Inwood        if (getConfig().showScrollingSuggestions()) {
111f5a8912d5da80378d38b667eba4aaa0555aea7bdMathew Inwood            mSearchActivityView.setMaxPromotedSuggestions(getConfig().getMaxPromotedSuggestions());
112fdb80c2962c88ac62dcd7ee7f2fab1857b61506bMathew Inwood        } else {
113fdb80c2962c88ac62dcd7ee7f2fab1857b61506bMathew Inwood            mSearchActivityView.limitSuggestionsToViewHeight();
114fdb80c2962c88ac62dcd7ee7f2fab1857b61506bMathew Inwood        }
115f5a8912d5da80378d38b667eba4aaa0555aea7bdMathew Inwood        if (getConfig().showScrollingResults()) {
116f5a8912d5da80378d38b667eba4aaa0555aea7bdMathew Inwood            mSearchActivityView.setMaxPromotedResults(getConfig().getMaxPromotedSuggestions());
117f5a8912d5da80378d38b667eba4aaa0555aea7bdMathew Inwood        } else {
118f5a8912d5da80378d38b667eba4aaa0555aea7bdMathew Inwood            mSearchActivityView.limitResultsToViewHeight();
119f5a8912d5da80378d38b667eba4aaa0555aea7bdMathew Inwood        }
120848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
1217010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.setSearchClickListener(new SearchActivityView.SearchClickListener() {
1227010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            public boolean onSearchClicked(int method) {
1237010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                return SearchActivity.this.onSearchClicked(method);
1247010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            }
1257010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        });
1262617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
1277010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.setQueryListener(new SearchActivityView.QueryListener() {
1287010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            public void onQueryChanged() {
1297010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                updateSuggestionsBuffered();
1307010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            }
1317010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        });
132782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
1337010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.setSuggestionClickListener(new ClickHandler());
1347be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert
1357010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.setSettingsButtonClickListener(new View.OnClickListener() {
1367010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            public void onClick(View v) {
1377010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                onSettingsClicked();
1387010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            }
1397010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        });
140848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
1417010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.setVoiceSearchButtonClickListener(new View.OnClickListener() {
1427010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            public void onClick(View view) {
1437010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert                onVoiceSearchClicked();
1447010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            }
1457010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        });
1469ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
147e833f84eee7ab575c8d53dec9b133fa5de9c7e6dMathew Inwood        View.OnClickListener finishOnClick = new View.OnClickListener() {
1489e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood            public void onClick(View v) {
1499e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood                finish();
1509e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood            }
151e833f84eee7ab575c8d53dec9b133fa5de9c7e6dMathew Inwood        };
152e833f84eee7ab575c8d53dec9b133fa5de9c7e6dMathew Inwood        mSearchActivityView.setExitClickListener(finishOnClick);
153e833f84eee7ab575c8d53dec9b133fa5de9c7e6dMathew Inwood        mSearchActivityView.setEmptySpaceClickListener(finishOnClick);
1549e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood
1559ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // First get setup from intent
1569ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        Intent intent = getIntent();
1579ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        setupFromIntent(intent);
1589ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // Then restore any saved instance state
1599ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        restoreInstanceState(savedInstanceState);
1609ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
161713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        // Do this at the end, to avoid updating the list view when setSource()
162713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        // is called.
1637010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.start();
16421bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert
16521bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        mCorporaObserver = new CorporaObserver();
16621bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        getCorpora().registerDataSetObserver(mCorporaObserver);
16798cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood        recordOnCreateDone();
1689ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    }
169713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
1705880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert    protected SearchActivityView setupContentView() {
1716ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert        setContentView(R.layout.search_activity);
1725880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert        return (SearchActivityView) findViewById(R.id.search_activity_view);
1735880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert    }
1745880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert
1755880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert    protected SearchActivityView getSearchActivityView() {
1765880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert        return mSearchActivityView;
1776ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert    }
1786ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert
17911234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert    private void startMethodTracing() {
18011234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        File traceDir = getDir("traces", 0);
18111234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        String traceFile = new File(traceDir, "qsb.trace").getAbsolutePath();
18211234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        Debug.startMethodTracing(traceFile);
18311234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert    }
18411234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert
1859ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    @Override
1869ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    protected void onNewIntent(Intent intent) {
187839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        if (DBG) Log.d(TAG, "onNewIntent()");
188ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        recordStartTime();
1899ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        setIntent(intent);
1909ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        setupFromIntent(intent);
1919ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    }
1929ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
193ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private void recordStartTime() {
194f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        mStartLatencyTracker = new LatencyTracker();
19598cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood        mOnCreateTracker = new LatencyTracker();
196ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mStarting = true;
197ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mTookAction = false;
198ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    }
199ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
20098cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood    private void recordOnCreateDone() {
20198cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood        mOnCreateLatency = mOnCreateTracker.getLatency();
20298cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood    }
20398cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood
2049ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    protected void restoreInstanceState(Bundle savedInstanceState) {
2059ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        if (savedInstanceState == null) return;
206fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        String corpusName = savedInstanceState.getString(INSTANCE_KEY_CORPUS);
207839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        String query = savedInstanceState.getString(INSTANCE_KEY_QUERY);
20821bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        setCorpus(corpusName);
209839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        setQuery(query, false);
210713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    }
211713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
212713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    @Override
2139ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    protected void onSaveInstanceState(Bundle outState) {
2149ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        super.onSaveInstanceState(outState);
2159ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // We don't save appSearchData, since we always get the value
2169ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // from the intent and the user can't change it.
217fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
21821bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        outState.putString(INSTANCE_KEY_CORPUS, getCorpusName());
219839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        outState.putString(INSTANCE_KEY_QUERY, getQuery());
220713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    }
221713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
222713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    private void setupFromIntent(Intent intent) {
223713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        if (DBG) Log.d(TAG, "setupFromIntent(" + intent.toUri(0) + ")");
22421bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        String corpusName = getCorpusNameFromUri(intent.getData());
2252617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        String query = intent.getStringExtra(SearchManager.QUERY);
2262617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        Bundle appSearchData = intent.getBundleExtra(SearchManager.APP_DATA);
227839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        boolean selectAll = intent.getBooleanExtra(SearchManager.EXTRA_SELECT_QUERY, false);
2282617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
22921bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        setCorpus(corpusName);
230839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        setQuery(query, selectAll);
231c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        mAppSearchData = appSearchData;
2322617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
23311c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert        if (startedIntoCorpusSelectionDialog()) {
2340a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood            mSearchActivityView.showCorpusSelectionDialog();
2352617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        }
2369ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    }
2379ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
23811c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert    public boolean startedIntoCorpusSelectionDialog() {
23911c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert        return INTENT_ACTION_QSB_AND_SELECT_CORPUS.equals(getIntent().getAction());
24011c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert    }
24111c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert
242dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    /**
243dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert     * Removes corpus selector intent action, so that BACK works normally after
244dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert     * dismissing and reopening the corpus selector.
245dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert     */
2460a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    public void clearStartedIntoCorpusSelectionDialog() {
247dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        Intent oldIntent = getIntent();
248dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        if (SearchActivity.INTENT_ACTION_QSB_AND_SELECT_CORPUS.equals(oldIntent.getAction())) {
249dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            Intent newIntent = new Intent(oldIntent);
250dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            newIntent.setAction(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
251dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            setIntent(newIntent);
252dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        }
253dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    }
254dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert
255fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public static Uri getCorpusUri(Corpus corpus) {
256fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (corpus == null) return null;
257fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return new Uri.Builder()
258fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                .scheme(SCHEME_CORPUS)
259fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                .authority(corpus.getName())
260fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                .build();
261fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
262fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
26321bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    private String getCorpusNameFromUri(Uri uri) {
264fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (uri == null) return null;
265fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (!SCHEME_CORPUS.equals(uri.getScheme())) return null;
26621bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        return uri.getAuthority();
267fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
268fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
2690a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    private Corpus getCorpus() {
2700a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        return mSearchActivityView.getCorpus();
271713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    }
272713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
2730a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    private String getCorpusName() {
2740a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        return mSearchActivityView.getCorpusName();
275f165f2d6c6f8173b94937ae3202f0b638348dffdBjorn Bringert    }
276f165f2d6c6f8173b94937ae3202f0b638348dffdBjorn Bringert
2770a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    private void setCorpus(String name) {
2780a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        mSearchActivityView.setCorpus(name);
27921bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    }
28021bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert
2813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private QsbApplication getQsbApplication() {
28249fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        return QsbApplication.get(this);
2833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
2843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
2854ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    private Config getConfig() {
2864ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert        return getQsbApplication().getConfig();
2874ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    }
2884ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert
28996fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert    protected SearchSettings getSettings() {
29096fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        return getQsbApplication().getSettings();
29196fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert    }
29296fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert
293b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    private Corpora getCorpora() {
294b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        return getQsbApplication().getCorpora();
295fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
296fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
297b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    private CorpusRanker getCorpusRanker() {
298b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        return getQsbApplication().getCorpusRanker();
2993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
301b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    private ShortcutRepository getShortcutRepository() {
302b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        return getQsbApplication().getShortcutRepository();
303848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
304848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
305b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    private SuggestionsProvider getSuggestionsProvider() {
306b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        return getQsbApplication().getSuggestionsProvider();
30747d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert    }
30847d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert
309ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private Logger getLogger() {
310ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        return getQsbApplication().getLogger();
311ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    }
312ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
3132607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood    @VisibleForTesting
3142607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood    public void setOnDestroyListener(OnDestroyListener l) {
3152607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood        mDestroyListener = l;
3162607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood    }
3172607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood
3183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
3193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void onDestroy() {
3203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "onDestroy()");
32121bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        getCorpora().unregisterDataSetObserver(mCorporaObserver);
3227010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.destroy();
3232607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood        super.onDestroy();
3242607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood        if (mDestroyListener != null) {
3252607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood            mDestroyListener.onDestroyed();
3262607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood        }
3273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
3293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
3303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void onStop() {
3319ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        if (DBG) Log.d(TAG, "onStop()");
332f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        if (!mTookAction) {
333848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            // TODO: This gets logged when starting other activities, e.g. by opening the search
334f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            // settings, or clicking a notification in the status bar.
335aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            // TODO we should log both sets of suggestions in 2-pane mode
336f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            getLogger().logExit(getCurrentSuggestions(), getQuery().length());
337f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        }
3389ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // Close all open suggestion cursors. The query will be redone in onResume()
3393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        // if we come back to this activity.
3407010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.clearSuggestions();
34194e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney        getQsbApplication().getShortcutRefresher().reset();
3420a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        mSearchActivityView.onStop();
3433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        super.onStop();
3443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
3463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
347839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert    protected void onRestart() {
348839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        if (DBG) Log.d(TAG, "onRestart()");
349839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        super.onRestart();
350839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert    }
351839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert
352839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert    @Override
353b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert    protected void onResume() {
3549ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        if (DBG) Log.d(TAG, "onResume()");
355b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert        super.onResume();
35611234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        updateSuggestionsBuffered();
3570a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        mSearchActivityView.onResume();
35811234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        if (TRACE) Debug.stopMethodTracing();
359b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert    }
360b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert
361b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert    @Override
3623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public boolean onCreateOptionsMenu(Menu menu) {
3633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        super.onCreateOptionsMenu(menu);
36496fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        getSettings().addMenuItems(menu);
36596fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        return true;
36696fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert    }
36796fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert
36896fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert    @Override
36996fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert    public boolean onPrepareOptionsMenu(Menu menu) {
37096fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        super.onPrepareOptionsMenu(menu);
37196fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        getSettings().updateMenuItems(menu);
3723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return true;
3733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
375d98911178013162737fbba74387b51d2a08b0493Amith Yamasani    @Override
376d98911178013162737fbba74387b51d2a08b0493Amith Yamasani    public void onWindowFocusChanged(boolean hasFocus) {
377d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        super.onWindowFocusChanged(hasFocus);
378d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        if (hasFocus) {
379d98911178013162737fbba74387b51d2a08b0493Amith Yamasani            // Launch the IME after a bit
380d98911178013162737fbba74387b51d2a08b0493Amith Yamasani            mHandler.postDelayed(mShowInputMethodTask, 0);
381d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        }
382d98911178013162737fbba74387b51d2a08b0493Amith Yamasani    }
383d98911178013162737fbba74387b51d2a08b0493Amith Yamasani
384713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    protected String getQuery() {
3857010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return mSearchActivityView.getQuery();
3863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
3887010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    protected void setQuery(String query, boolean selectAll) {
3897010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.setQuery(query, selectAll);
390e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    }
391e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert
3920a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    public CorpusSelectionDialog getCorpusSelectionDialog() {
3930a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        CorpusSelectionDialog dialog = createCorpusSelectionDialog();
3940a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        dialog.setOwnerActivity(this);
3950a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        dialog.setOnDismissListener(new CorpusSelectorDismissListener());
3960a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        return dialog;
3972617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert    }
3982617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
39923db3f9877e691568fe2c955fd9d4f48a2eb937aMathew Inwood    protected CorpusSelectionDialog createCorpusSelectionDialog() {
40096fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        return new CorpusSelectionDialog(this, getSettings());
40135c43805a450c17d5fc5e27dc073edc6e2cd7320Amith Yamasani    }
40235c43805a450c17d5fc5e27dc073edc6e2cd7320Amith Yamasani
403dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood    /**
404dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood     * @return true if a search was performed as a result of this click, false otherwise.
405dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood     */
406dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood    protected boolean onSearchClicked(int method) {
4073a7125b39b72f7417684c4d3040abeb4a81bd6b3Bjorn Bringert        String query = CharMatcher.WHITESPACE.trimAndCollapseFrom(getQuery(), ' ');
4083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "Search clicked, query=" + query);
409eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert
410eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert        // Don't do empty queries
411dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood        if (TextUtils.getTrimmedLength(query) == 0) return false;
412eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert
41381a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        Corpus searchCorpus = getSearchCorpus();
414dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood        if (searchCorpus == null) return false;
415c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
416ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mTookAction = true;
417c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
418c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Log search start
4190a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        getLogger().logSearch(getCorpus(), method, query.length());
420c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
421c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Create shortcut
422c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        SuggestionData searchShortcut = searchCorpus.createSearchShortcut(query);
423c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        if (searchShortcut != null) {
42493bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert            ListSuggestionCursor cursor = new ListSuggestionCursor(query);
425c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert            cursor.add(searchShortcut);
426c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert            getShortcutRepository().reportClick(cursor, 0);
427c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        }
428c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
429c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Start search
4309d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert        startSearch(searchCorpus, query);
4319d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert        return true;
4329d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert    }
4339d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert
4349d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert    protected void startSearch(Corpus searchCorpus, String query) {
435c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        Intent intent = searchCorpus.createSearchIntent(query, mAppSearchData);
43681a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        launchIntent(intent);
4373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
4383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
4393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void onVoiceSearchClicked() {
4403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "Voice Search clicked");
44181a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        Corpus searchCorpus = getSearchCorpus();
442c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        if (searchCorpus == null) return;
443c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
444535931433926d342c6277034cad91143ae28b72dBjorn Bringert        mTookAction = true;
445535931433926d342c6277034cad91143ae28b72dBjorn Bringert
446c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Log voice search start
447c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        getLogger().logVoiceSearch(searchCorpus);
448ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
449c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Start voice search
450c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        Intent intent = searchCorpus.createVoiceSearchIntent(mAppSearchData);
45181a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        launchIntent(intent);
45281a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert    }
45381a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert
454848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected void onSettingsClicked() {
45596fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        startActivity(getSettings().getSearchSettingsIntent());
456848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
457848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
458ca9c7b7bc0183aa1b6d160bf76597c96e70831f6Mathew Inwood    protected Corpus getSearchCorpus() {
4597010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return mSearchActivityView.getSearchCorpus();
460014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert    }
461014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert
462e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringert    protected SuggestionCursor getCurrentSuggestions() {
4637010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return mSearchActivityView.getCurrentSuggestions();
464782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    }
465782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
466848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected SuggestionCursor getCurrentSuggestions(SuggestionsAdapter adapter, int position) {
467848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        SuggestionCursor suggestions = adapter.getCurrentSuggestions();
4685f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (suggestions == null) {
4695f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert            return null;
4705f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        }
4715f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        int count = suggestions.getCount();
4725f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (position < 0 || position >= count) {
4735f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert            Log.w(TAG, "Invalid suggestion position " + position + ", count = " + count);
4745f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert            return null;
4755f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        }
4765f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        suggestions.moveTo(position);
4775f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        return suggestions;
4785f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert    }
4795f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert
4805f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert    protected Set<Corpus> getCurrentIncludedCorpora() {
4817010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        Suggestions suggestions = mSearchActivityView.getSuggestions();
482848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        return suggestions == null  ? null : suggestions.getIncludedCorpora();
4835f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert    }
4845f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert
48581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert    protected void launchIntent(Intent intent) {
48613b4f2dc4b339790c2b9b0220be47c8e77fd61eaMathew Inwood        if (DBG) Log.d(TAG, "launchIntent " + intent);
48781a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        if (intent == null) {
48881a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            return;
48981a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        }
49081a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        try {
49181a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            startActivity(intent);
4920fe82998ab9d499e99722b199f5e0db9fc12e433Mathew Inwood            if (!getConfig().keepSearchActivityInBackStack()) {
4930fe82998ab9d499e99722b199f5e0db9fc12e433Mathew Inwood                finish();
4940fe82998ab9d499e99722b199f5e0db9fc12e433Mathew Inwood            }
49581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        } catch (RuntimeException ex) {
49681a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            // Since the intents for suggestions specified by suggestion providers,
49781a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            // guard against them not being handled, not allowed, etc.
49881a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            Log.e(TAG, "Failed to start " + intent.toUri(0), ex);
49981a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        }
50081a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert    }
50181a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert
5027010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private boolean launchSuggestion(SuggestionsAdapter adapter, int position) {
503848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        SuggestionCursor suggestions = getCurrentSuggestions(adapter, position);
5045f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (suggestions == null) return false;
5056f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert
506fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (DBG) Log.d(TAG, "Launching suggestion " + position);
507ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mTookAction = true;
508e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringert
509c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Log suggestion click
510c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        getLogger().logSuggestionClick(position, suggestions, getCurrentIncludedCorpora(),
511c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert                Logger.SUGGESTION_CLICK_TYPE_LAUNCH);
512ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
513c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Create shortcut
514fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        getShortcutRepository().reportClick(suggestions, position);
515c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
516c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Launch intent
5179d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert        launchSuggestion(suggestions, position);
5189d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert
5199d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert        return true;
5209d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert    }
5219d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert
5229d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert    protected void launchSuggestion(SuggestionCursor suggestions, int position) {
52381a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        suggestions.moveTo(position);
52493bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert        Intent intent = SuggestionUtils.getSuggestionIntent(suggestions, mAppSearchData);
52581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        launchIntent(intent);
5263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
5273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
528fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    protected void removeFromHistory(SuggestionsAdapter adapter, int position) {
529fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        SuggestionCursor suggestions = getCurrentSuggestions(adapter, position);
530fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        if (suggestions == null) return;
531fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        removeFromHistory(suggestions, position);
532fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        // TODO: Log to event log?
533fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    }
534fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert
535fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    protected void removeFromHistory(SuggestionCursor suggestions, int position) {
536fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        removeShortcut(suggestions, position);
537fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        removeFromHistoryDone(true);
538fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    }
539fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert
540fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    protected void removeFromHistoryDone(boolean ok) {
541fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        Log.i(TAG, "Removed query from history, success=" + ok);
542fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        updateSuggestionsBuffered();
543fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        if (!ok) {
544fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert            Toast.makeText(this, R.string.remove_from_history_failed, Toast.LENGTH_SHORT).show();
545fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        }
546fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    }
547fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert
548fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    protected void removeShortcut(SuggestionCursor suggestions, int position) {
549fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        if (suggestions.isSuggestionShortcut()) {
550fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert            if (DBG) Log.d(TAG, "Removing suggestion " + position + " from shortcuts");
551fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert            getShortcutRepository().removeFromHistory(suggestions, position);
552fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        }
553fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    }
554fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert
555aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood    protected void clickedQuickContact(SuggestionsAdapter adapter, int position) {
556aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood        SuggestionCursor suggestions = getCurrentSuggestions(adapter, position);
557c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        if (suggestions == null) return;
558c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert
559c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        if (DBG) Log.d(TAG, "Used suggestion " + position);
560c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        mTookAction = true;
561c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert
562c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        // Log suggestion click
563c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        getLogger().logSuggestionClick(position, suggestions, getCurrentIncludedCorpora(),
564c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert                Logger.SUGGESTION_CLICK_TYPE_QUICK_CONTACT);
565c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert
566c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        // Create shortcut
567c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        getShortcutRepository().reportClick(suggestions, position);
568c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert    }
569c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert
570848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected void refineSuggestion(SuggestionsAdapter adapter, int position) {
5715f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (DBG) Log.d(TAG, "query refine clicked, pos " + position);
572848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        SuggestionCursor suggestions = getCurrentSuggestions(adapter, position);
5735f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (suggestions == null) {
5745f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert            return;
5755f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        }
5765f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        String query = suggestions.getSuggestionQuery();
5775f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (TextUtils.isEmpty(query)) {
5785f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert            return;
5795f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        }
5805f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert
5815f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        // Log refine click
582c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        getLogger().logSuggestionClick(position, suggestions, getCurrentIncludedCorpora(),
583c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert                Logger.SUGGESTION_CLICK_TYPE_REFINE);
5845f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert
5855f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        // Put query + space in query text view
5865f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        String queryWithSpace = query + ' ';
5875f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        setQuery(queryWithSpace, false);
588dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert        updateSuggestions();
5897010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.focusQueryTextView();
5903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
5913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
5924ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    private void updateSuggestionsBuffered() {
5937f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert        if (DBG) Log.d(TAG, "updateSuggestionsBuffered()");
594d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        mHandler.removeCallbacks(mUpdateSuggestionsTask);
5954ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert        long delay = getConfig().getTypingUpdateSuggestionsDelayMillis();
596d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        mHandler.postDelayed(mUpdateSuggestionsTask, delay);
5974ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    }
5984ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert
599b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    private void gotSuggestions(Suggestions suggestions) {
60011234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        if (mStarting) {
60111234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert            mStarting = false;
60211234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert            String source = getIntent().getStringExtra(Search.SOURCE);
60311234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert            int latency = mStartLatencyTracker.getLatency();
60498cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood            getLogger().logStart(mOnCreateLatency, latency, source, getCorpus(),
605848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani                    suggestions == null ? null : suggestions.getExpectedCorpora());
606b5560dbe16a8fb3148b0fb24c73836bf2e84dd61Mathew Inwood            getQsbApplication().onStartupComplete();
60711234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        }
608848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
609848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
6106859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    private void getCorporaToQuery(Consumer<List<Corpus>> consumer) {
611dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert        Corpus corpus = getCorpus();
612dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert        if (corpus == null) {
613dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert            getCorpusRanker().getCorporaInAll(Consumers.createAsyncConsumer(mHandler, consumer));
614dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert        } else {
615dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert            List<Corpus> corpora = new ArrayList<Corpus>();
616dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert            Corpus searchCorpus = getSearchCorpus();
617dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert            if (searchCorpus != null) corpora.add(searchCorpus);
618dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert            consumer.consume(corpora);
619dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert        }
6204572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood    }
6214572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood
622b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert    protected void getShortcutsForQuery(String query, Collection<Corpus> corporaToQuery,
623b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert            final Suggestions suggestions) {
624b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        ShortcutRepository shortcutRepo = getShortcutRepository();
625b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert        if (shortcutRepo == null) return;
626e15fe38f0142174d223bfda0cd87d1a749a85facMathew Inwood        if (query.length() == 0 && !getConfig().showShortcutsForZeroQuery()) {
627e15fe38f0142174d223bfda0cd87d1a749a85facMathew Inwood            return;
628e15fe38f0142174d223bfda0cd87d1a749a85facMathew Inwood        }
629b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert        Consumer<ShortcutCursor> consumer = Consumers.createAsyncCloseableConsumer(mHandler,
630b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert                new Consumer<ShortcutCursor>() {
631b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert            public boolean consume(ShortcutCursor shortcuts) {
632b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert                suggestions.setShortcuts(shortcuts);
633b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert                return true;
634b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert            }
635b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert        });
6368749e77dddec9e7984ee86a7be6f5ba4fce44362Bjorn Bringert        shortcutRepo.getShortcutsForQuery(query, corporaToQuery,
6378749e77dddec9e7984ee86a7be6f5ba4fce44362Bjorn Bringert                getSettings().allowWebSearchShortcuts(), consumer);
638b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    }
63911234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert
640dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert    public void updateSuggestions() {
6417f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert        if (DBG) Log.d(TAG, "updateSuggestions()");
6427f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert        final String query = CharMatcher.WHITESPACE.trimLeadingFrom(getQuery());
6434572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood        getQsbApplication().getSourceTaskExecutor().cancelPendingTasks();
6446859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        getCorporaToQuery(new Consumer<List<Corpus>>(){
6456859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            @Override
6466859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            public boolean consume(List<Corpus> corporaToQuery) {
6476859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert                updateSuggestions(query, corporaToQuery);
6486859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert                return true;
6496859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            }
6506859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        });
6516859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    }
652b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert
6536859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    protected void updateSuggestions(String query, List<Corpus> corporaToQuery) {
6547f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert        if (DBG) Log.d(TAG, "updateSuggestions(\"" + query+"\"," + corporaToQuery + ")");
655b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        Suggestions suggestions = getSuggestionsProvider().getSuggestions(
656b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert                query, corporaToQuery);
657b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert        getShortcutsForQuery(query, corporaToQuery, suggestions);
658b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert
659b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        // Log start latency if this is the first suggestions update
660b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        gotSuggestions(suggestions);
661b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert
6625880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert        showSuggestions(suggestions);
6635880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert    }
6645880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert
6655880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert    protected void showSuggestions(Suggestions suggestions) {
6667010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.setSuggestions(suggestions);
667185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert    }
668185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
669185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert    private class ClickHandler implements SuggestionClickListener {
670848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
6717010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public void onSuggestionQuickContactClicked(SuggestionsAdapter adapter, int position) {
6727010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            clickedQuickContact(adapter, position);
673848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
6743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
6757010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public void onSuggestionClicked(SuggestionsAdapter adapter, int position) {
6767010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            launchSuggestion(adapter, position);
677848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
678145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert
679fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        public void onSuggestionRemoveFromHistoryClicked(SuggestionsAdapter adapter, int position) {
680fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert            removeFromHistory(adapter, position);
681848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
6823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
6837010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public void onSuggestionQueryRefineClicked(SuggestionsAdapter adapter, int position) {
6847010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            refineSuggestion(adapter, position);
6852617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        }
686f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    }
687f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert
688dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    private class CorpusSelectorDismissListener implements DialogInterface.OnDismissListener {
689dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        public void onDismiss(DialogInterface dialog) {
690dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            if (DBG) Log.d(TAG, "Corpus selector dismissed");
691dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            clearStartedIntoCorpusSelectionDialog();
692dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        }
693dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    }
694dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert
69521bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    private class CorporaObserver extends DataSetObserver {
69621bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        @Override
69721bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        public void onChanged() {
69821bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert            setCorpus(getCorpusName());
699dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert            updateSuggestions();
70021bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        }
70121bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    }
70221bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert
7032607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood    public interface OnDestroyListener {
7042607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood        void onDestroyed();
7052607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood    }
7062607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood
7073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert}
708