SearchActivity.java revision 98cbee7f6266509a0805b3fef060f01caaef69e3
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
1479e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood        mSearchActivityView.setExitClickListener(new View.OnClickListener() {
1489e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood            public void onClick(View v) {
1499e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood                finish();
1509e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood            }
1519e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood        });
1529e46c057d7f88d2a899e124f96d266c54250bb45Mathew Inwood
1539ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // First get setup from intent
1549ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        Intent intent = getIntent();
1559ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        setupFromIntent(intent);
1569ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // Then restore any saved instance state
1579ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        restoreInstanceState(savedInstanceState);
1589ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
159713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        // Do this at the end, to avoid updating the list view when setSource()
160713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        // is called.
1617010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.start();
16221bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert
16321bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        mCorporaObserver = new CorporaObserver();
16421bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        getCorpora().registerDataSetObserver(mCorporaObserver);
16598cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood        recordOnCreateDone();
1669ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    }
167713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
1685880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert    protected SearchActivityView setupContentView() {
1696ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert        setContentView(R.layout.search_activity);
1705880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert        return (SearchActivityView) findViewById(R.id.search_activity_view);
1715880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert    }
1725880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert
1735880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert    protected SearchActivityView getSearchActivityView() {
1745880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert        return mSearchActivityView;
1756ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert    }
1766ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert
17711234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert    private void startMethodTracing() {
17811234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        File traceDir = getDir("traces", 0);
17911234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        String traceFile = new File(traceDir, "qsb.trace").getAbsolutePath();
18011234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        Debug.startMethodTracing(traceFile);
18111234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert    }
18211234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert
1839ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    @Override
1849ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    protected void onNewIntent(Intent intent) {
185839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        if (DBG) Log.d(TAG, "onNewIntent()");
186ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        recordStartTime();
1879ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        setIntent(intent);
1889ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        setupFromIntent(intent);
1899ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    }
1909ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
191ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private void recordStartTime() {
192f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        mStartLatencyTracker = new LatencyTracker();
19398cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood        mOnCreateTracker = new LatencyTracker();
194ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mStarting = true;
195ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mTookAction = false;
196ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    }
197ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
19898cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood    private void recordOnCreateDone() {
19998cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood        mOnCreateLatency = mOnCreateTracker.getLatency();
20098cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood    }
20198cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood
2029ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    protected void restoreInstanceState(Bundle savedInstanceState) {
2039ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        if (savedInstanceState == null) return;
204fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        String corpusName = savedInstanceState.getString(INSTANCE_KEY_CORPUS);
205839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        String query = savedInstanceState.getString(INSTANCE_KEY_QUERY);
20621bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        setCorpus(corpusName);
207839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        setQuery(query, false);
208713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    }
209713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
210713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    @Override
2119ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    protected void onSaveInstanceState(Bundle outState) {
2129ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        super.onSaveInstanceState(outState);
2139ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // We don't save appSearchData, since we always get the value
2149ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // from the intent and the user can't change it.
215fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
21621bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        outState.putString(INSTANCE_KEY_CORPUS, getCorpusName());
217839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        outState.putString(INSTANCE_KEY_QUERY, getQuery());
218713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    }
219713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
220713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    private void setupFromIntent(Intent intent) {
221713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert        if (DBG) Log.d(TAG, "setupFromIntent(" + intent.toUri(0) + ")");
22221bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        String corpusName = getCorpusNameFromUri(intent.getData());
2232617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        String query = intent.getStringExtra(SearchManager.QUERY);
2242617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        Bundle appSearchData = intent.getBundleExtra(SearchManager.APP_DATA);
225839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        boolean selectAll = intent.getBooleanExtra(SearchManager.EXTRA_SELECT_QUERY, false);
2262617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
22721bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        setCorpus(corpusName);
228839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        setQuery(query, selectAll);
229c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        mAppSearchData = appSearchData;
2302617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
23111c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert        if (startedIntoCorpusSelectionDialog()) {
2320a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood            mSearchActivityView.showCorpusSelectionDialog();
2332617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        }
2349ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert    }
2359ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert
23611c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert    public boolean startedIntoCorpusSelectionDialog() {
23711c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert        return INTENT_ACTION_QSB_AND_SELECT_CORPUS.equals(getIntent().getAction());
23811c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert    }
23911c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert
240dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    /**
241dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert     * Removes corpus selector intent action, so that BACK works normally after
242dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert     * dismissing and reopening the corpus selector.
243dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert     */
2440a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    public void clearStartedIntoCorpusSelectionDialog() {
245dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        Intent oldIntent = getIntent();
246dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        if (SearchActivity.INTENT_ACTION_QSB_AND_SELECT_CORPUS.equals(oldIntent.getAction())) {
247dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            Intent newIntent = new Intent(oldIntent);
248dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            newIntent.setAction(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
249dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            setIntent(newIntent);
250dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        }
251dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    }
252dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert
253fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public static Uri getCorpusUri(Corpus corpus) {
254fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (corpus == null) return null;
255fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return new Uri.Builder()
256fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                .scheme(SCHEME_CORPUS)
257fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                .authority(corpus.getName())
258fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                .build();
259fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
260fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
26121bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    private String getCorpusNameFromUri(Uri uri) {
262fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (uri == null) return null;
263fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (!SCHEME_CORPUS.equals(uri.getScheme())) return null;
26421bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        return uri.getAuthority();
265fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
266fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
2670a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    private Corpus getCorpus() {
2680a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        return mSearchActivityView.getCorpus();
269713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    }
270713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert
2710a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    private String getCorpusName() {
2720a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        return mSearchActivityView.getCorpusName();
273f165f2d6c6f8173b94937ae3202f0b638348dffdBjorn Bringert    }
274f165f2d6c6f8173b94937ae3202f0b638348dffdBjorn Bringert
2750a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    private void setCorpus(String name) {
2760a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        mSearchActivityView.setCorpus(name);
27721bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    }
27821bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert
2793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private QsbApplication getQsbApplication() {
28049fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        return QsbApplication.get(this);
2813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
2823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
2834ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    private Config getConfig() {
2844ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert        return getQsbApplication().getConfig();
2854ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    }
2864ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert
28796fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert    protected SearchSettings getSettings() {
28896fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        return getQsbApplication().getSettings();
28996fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert    }
29096fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert
291b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    private Corpora getCorpora() {
292b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        return getQsbApplication().getCorpora();
293fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
294fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
295b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    private CorpusRanker getCorpusRanker() {
296b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        return getQsbApplication().getCorpusRanker();
2973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
2983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
299b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    private ShortcutRepository getShortcutRepository() {
300b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        return getQsbApplication().getShortcutRepository();
301848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
302848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
303b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    private SuggestionsProvider getSuggestionsProvider() {
304b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        return getQsbApplication().getSuggestionsProvider();
30547d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert    }
30647d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert
307ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private Logger getLogger() {
308ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        return getQsbApplication().getLogger();
309ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    }
310ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
3112607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood    @VisibleForTesting
3122607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood    public void setOnDestroyListener(OnDestroyListener l) {
3132607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood        mDestroyListener = l;
3142607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood    }
3152607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood
3163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
3173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void onDestroy() {
3183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "onDestroy()");
31921bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        getCorpora().unregisterDataSetObserver(mCorporaObserver);
3207010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.destroy();
3212607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood        super.onDestroy();
3222607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood        if (mDestroyListener != null) {
3232607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood            mDestroyListener.onDestroyed();
3242607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood        }
3253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
3273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
3283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void onStop() {
3299ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        if (DBG) Log.d(TAG, "onStop()");
330f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        if (!mTookAction) {
331848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            // TODO: This gets logged when starting other activities, e.g. by opening the search
332f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            // settings, or clicking a notification in the status bar.
333aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood            // TODO we should log both sets of suggestions in 2-pane mode
334f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            getLogger().logExit(getCurrentSuggestions(), getQuery().length());
335f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert        }
3369ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        // Close all open suggestion cursors. The query will be redone in onResume()
3373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        // if we come back to this activity.
3387010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.clearSuggestions();
33994e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney        getQsbApplication().getShortcutRefresher().reset();
3400a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        mSearchActivityView.onStop();
3413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        super.onStop();
3423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
3443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
345839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert    protected void onRestart() {
346839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        if (DBG) Log.d(TAG, "onRestart()");
347839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert        super.onRestart();
348839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert    }
349839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert
350839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert    @Override
351b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert    protected void onResume() {
3529ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert        if (DBG) Log.d(TAG, "onResume()");
353b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert        super.onResume();
35411234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        updateSuggestionsBuffered();
3550a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        mSearchActivityView.onResume();
35611234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        if (TRACE) Debug.stopMethodTracing();
357b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert    }
358b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert
359b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert    @Override
3603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public boolean onCreateOptionsMenu(Menu menu) {
3613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        super.onCreateOptionsMenu(menu);
36296fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        getSettings().addMenuItems(menu);
36396fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        return true;
36496fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert    }
36596fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert
36696fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert    @Override
36796fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert    public boolean onPrepareOptionsMenu(Menu menu) {
36896fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        super.onPrepareOptionsMenu(menu);
36996fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        getSettings().updateMenuItems(menu);
3703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return true;
3713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
373d98911178013162737fbba74387b51d2a08b0493Amith Yamasani    @Override
374d98911178013162737fbba74387b51d2a08b0493Amith Yamasani    public void onWindowFocusChanged(boolean hasFocus) {
375d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        super.onWindowFocusChanged(hasFocus);
376d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        if (hasFocus) {
377d98911178013162737fbba74387b51d2a08b0493Amith Yamasani            // Launch the IME after a bit
378d98911178013162737fbba74387b51d2a08b0493Amith Yamasani            mHandler.postDelayed(mShowInputMethodTask, 0);
379d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        }
380d98911178013162737fbba74387b51d2a08b0493Amith Yamasani    }
381d98911178013162737fbba74387b51d2a08b0493Amith Yamasani
382713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert    protected String getQuery() {
3837010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return mSearchActivityView.getQuery();
3843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
3867010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    protected void setQuery(String query, boolean selectAll) {
3877010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.setQuery(query, selectAll);
388e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert    }
389e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert
3900a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood    public CorpusSelectionDialog getCorpusSelectionDialog() {
3910a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        CorpusSelectionDialog dialog = createCorpusSelectionDialog();
3920a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        dialog.setOwnerActivity(this);
3930a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        dialog.setOnDismissListener(new CorpusSelectorDismissListener());
3940a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        return dialog;
3952617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert    }
3962617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert
39723db3f9877e691568fe2c955fd9d4f48a2eb937aMathew Inwood    protected CorpusSelectionDialog createCorpusSelectionDialog() {
39896fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        return new CorpusSelectionDialog(this, getSettings());
39935c43805a450c17d5fc5e27dc073edc6e2cd7320Amith Yamasani    }
40035c43805a450c17d5fc5e27dc073edc6e2cd7320Amith Yamasani
401dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood    /**
402dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood     * @return true if a search was performed as a result of this click, false otherwise.
403dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood     */
404dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood    protected boolean onSearchClicked(int method) {
4053a7125b39b72f7417684c4d3040abeb4a81bd6b3Bjorn Bringert        String query = CharMatcher.WHITESPACE.trimAndCollapseFrom(getQuery(), ' ');
4063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "Search clicked, query=" + query);
407eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert
408eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert        // Don't do empty queries
409dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood        if (TextUtils.getTrimmedLength(query) == 0) return false;
410eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert
41181a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        Corpus searchCorpus = getSearchCorpus();
412dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood        if (searchCorpus == null) return false;
413c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
414ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mTookAction = true;
415c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
416c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Log search start
4170a73d81f02118d0343d3f1c9219a8354466f72b3Mathew Inwood        getLogger().logSearch(getCorpus(), method, query.length());
418c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
419c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Create shortcut
420c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        SuggestionData searchShortcut = searchCorpus.createSearchShortcut(query);
421c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        if (searchShortcut != null) {
42293bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert            ListSuggestionCursor cursor = new ListSuggestionCursor(query);
423c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert            cursor.add(searchShortcut);
424c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert            getShortcutRepository().reportClick(cursor, 0);
425c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        }
426c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
427c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Start search
4289d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert        startSearch(searchCorpus, query);
4299d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert        return true;
4309d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert    }
4319d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert
4329d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert    protected void startSearch(Corpus searchCorpus, String query) {
433c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        Intent intent = searchCorpus.createSearchIntent(query, mAppSearchData);
43481a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        launchIntent(intent);
4353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
4363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
4373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void onVoiceSearchClicked() {
4383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (DBG) Log.d(TAG, "Voice Search clicked");
43981a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        Corpus searchCorpus = getSearchCorpus();
440c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        if (searchCorpus == null) return;
441c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
442535931433926d342c6277034cad91143ae28b72dBjorn Bringert        mTookAction = true;
443535931433926d342c6277034cad91143ae28b72dBjorn Bringert
444c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Log voice search start
445c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        getLogger().logVoiceSearch(searchCorpus);
446ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
447c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Start voice search
448c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        Intent intent = searchCorpus.createVoiceSearchIntent(mAppSearchData);
44981a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        launchIntent(intent);
45081a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert    }
45181a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert
452848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected void onSettingsClicked() {
45396fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        startActivity(getSettings().getSearchSettingsIntent());
454848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
455848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
456ca9c7b7bc0183aa1b6d160bf76597c96e70831f6Mathew Inwood    protected Corpus getSearchCorpus() {
4577010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return mSearchActivityView.getSearchCorpus();
458014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert    }
459014e0d0c0a5102b7cc1c5576a3af25a646731dd0Bjorn Bringert
460e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringert    protected SuggestionCursor getCurrentSuggestions() {
4617010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        return mSearchActivityView.getCurrentSuggestions();
462782dd228e78e9294692d639597f96c26283968bbBjorn Bringert    }
463782dd228e78e9294692d639597f96c26283968bbBjorn Bringert
464848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected SuggestionCursor getCurrentSuggestions(SuggestionsAdapter adapter, int position) {
465848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        SuggestionCursor suggestions = adapter.getCurrentSuggestions();
4665f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (suggestions == null) {
4675f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert            return null;
4685f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        }
4695f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        int count = suggestions.getCount();
4705f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (position < 0 || position >= count) {
4715f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert            Log.w(TAG, "Invalid suggestion position " + position + ", count = " + count);
4725f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert            return null;
4735f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        }
4745f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        suggestions.moveTo(position);
4755f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        return suggestions;
4765f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert    }
4775f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert
4785f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert    protected Set<Corpus> getCurrentIncludedCorpora() {
4797010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        Suggestions suggestions = mSearchActivityView.getSuggestions();
480848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        return suggestions == null  ? null : suggestions.getIncludedCorpora();
4815f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert    }
4825f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert
48381a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert    protected void launchIntent(Intent intent) {
48413b4f2dc4b339790c2b9b0220be47c8e77fd61eaMathew Inwood        if (DBG) Log.d(TAG, "launchIntent " + intent);
48581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        if (intent == null) {
48681a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            return;
48781a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        }
48881a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        try {
48981a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            startActivity(intent);
4900fe82998ab9d499e99722b199f5e0db9fc12e433Mathew Inwood            if (!getConfig().keepSearchActivityInBackStack()) {
4910fe82998ab9d499e99722b199f5e0db9fc12e433Mathew Inwood                finish();
4920fe82998ab9d499e99722b199f5e0db9fc12e433Mathew Inwood            }
49381a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        } catch (RuntimeException ex) {
49481a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            // Since the intents for suggestions specified by suggestion providers,
49581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            // guard against them not being handled, not allowed, etc.
49681a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            Log.e(TAG, "Failed to start " + intent.toUri(0), ex);
49781a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        }
49881a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert    }
49981a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert
5007010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert    private boolean launchSuggestion(SuggestionsAdapter adapter, int position) {
501848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        SuggestionCursor suggestions = getCurrentSuggestions(adapter, position);
5025f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (suggestions == null) return false;
5036f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert
504fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (DBG) Log.d(TAG, "Launching suggestion " + position);
505ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        mTookAction = true;
506e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringert
507c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Log suggestion click
508c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        getLogger().logSuggestionClick(position, suggestions, getCurrentIncludedCorpora(),
509c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert                Logger.SUGGESTION_CLICK_TYPE_LAUNCH);
510ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
511c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Create shortcut
512fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        getShortcutRepository().reportClick(suggestions, position);
513c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert
514c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert        // Launch intent
5159d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert        launchSuggestion(suggestions, position);
5169d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert
5179d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert        return true;
5189d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert    }
5199d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert
5209d731c0bae275ee9b1c87b679820259c18cc68c8Bjorn Bringert    protected void launchSuggestion(SuggestionCursor suggestions, int position) {
52181a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        suggestions.moveTo(position);
52293bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert        Intent intent = SuggestionUtils.getSuggestionIntent(suggestions, mAppSearchData);
52381a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        launchIntent(intent);
5243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
5253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
526fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    protected void removeFromHistory(SuggestionsAdapter adapter, int position) {
527fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        SuggestionCursor suggestions = getCurrentSuggestions(adapter, position);
528fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        if (suggestions == null) return;
529fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        removeFromHistory(suggestions, position);
530fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        // TODO: Log to event log?
531fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    }
532fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert
533fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    protected void removeFromHistory(SuggestionCursor suggestions, int position) {
534fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        removeShortcut(suggestions, position);
535fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        removeFromHistoryDone(true);
536fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    }
537fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert
538fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    protected void removeFromHistoryDone(boolean ok) {
539fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        Log.i(TAG, "Removed query from history, success=" + ok);
540fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        updateSuggestionsBuffered();
541fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        if (!ok) {
542fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert            Toast.makeText(this, R.string.remove_from_history_failed, Toast.LENGTH_SHORT).show();
543fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        }
544fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    }
545fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert
546fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    protected void removeShortcut(SuggestionCursor suggestions, int position) {
547fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        if (suggestions.isSuggestionShortcut()) {
548fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert            if (DBG) Log.d(TAG, "Removing suggestion " + position + " from shortcuts");
549fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert            getShortcutRepository().removeFromHistory(suggestions, position);
550fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        }
551fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert    }
552fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert
553aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood    protected void clickedQuickContact(SuggestionsAdapter adapter, int position) {
554aa7d79792baca59eb7afe00ea27abc5176ddd34bMathew Inwood        SuggestionCursor suggestions = getCurrentSuggestions(adapter, position);
555c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        if (suggestions == null) return;
556c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert
557c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        if (DBG) Log.d(TAG, "Used suggestion " + position);
558c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        mTookAction = true;
559c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert
560c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        // Log suggestion click
561c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        getLogger().logSuggestionClick(position, suggestions, getCurrentIncludedCorpora(),
562c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert                Logger.SUGGESTION_CLICK_TYPE_QUICK_CONTACT);
563c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert
564c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        // Create shortcut
565c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        getShortcutRepository().reportClick(suggestions, position);
566c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert    }
567c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert
568848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected void refineSuggestion(SuggestionsAdapter adapter, int position) {
5695f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (DBG) Log.d(TAG, "query refine clicked, pos " + position);
570848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        SuggestionCursor suggestions = getCurrentSuggestions(adapter, position);
5715f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (suggestions == null) {
5725f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert            return;
5735f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        }
5745f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        String query = suggestions.getSuggestionQuery();
5755f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        if (TextUtils.isEmpty(query)) {
5765f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert            return;
5775f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        }
5785f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert
5795f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        // Log refine click
580c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert        getLogger().logSuggestionClick(position, suggestions, getCurrentIncludedCorpora(),
581c020c1844b0fb3a825e8a6fa6ad96288bc432fbcBjorn Bringert                Logger.SUGGESTION_CLICK_TYPE_REFINE);
5825f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert
5835f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        // Put query + space in query text view
5845f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        String queryWithSpace = query + ' ';
5855f71d5746ec042ad2e5c1eee8c83514f92534372Bjorn Bringert        setQuery(queryWithSpace, false);
586dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert        updateSuggestions();
5877010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.focusQueryTextView();
5883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
5893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
5904ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    private void updateSuggestionsBuffered() {
5917f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert        if (DBG) Log.d(TAG, "updateSuggestionsBuffered()");
592d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        mHandler.removeCallbacks(mUpdateSuggestionsTask);
5934ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert        long delay = getConfig().getTypingUpdateSuggestionsDelayMillis();
594d98911178013162737fbba74387b51d2a08b0493Amith Yamasani        mHandler.postDelayed(mUpdateSuggestionsTask, delay);
5954ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert    }
5964ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert
597b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    private void gotSuggestions(Suggestions suggestions) {
59811234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        if (mStarting) {
59911234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert            mStarting = false;
60011234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert            String source = getIntent().getStringExtra(Search.SOURCE);
60111234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert            int latency = mStartLatencyTracker.getLatency();
60298cbee7f6266509a0805b3fef060f01caaef69e3Mathew Inwood            getLogger().logStart(mOnCreateLatency, latency, source, getCorpus(),
603848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani                    suggestions == null ? null : suggestions.getExpectedCorpora());
604b5560dbe16a8fb3148b0fb24c73836bf2e84dd61Mathew Inwood            getQsbApplication().onStartupComplete();
60511234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert        }
606848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
607848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
6086859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    private void getCorporaToQuery(Consumer<List<Corpus>> consumer) {
609dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert        Corpus corpus = getCorpus();
610dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert        if (corpus == null) {
611dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert            getCorpusRanker().getCorporaInAll(Consumers.createAsyncConsumer(mHandler, consumer));
612dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert        } else {
613dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert            List<Corpus> corpora = new ArrayList<Corpus>();
614dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert            Corpus searchCorpus = getSearchCorpus();
615dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert            if (searchCorpus != null) corpora.add(searchCorpus);
616dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert            consumer.consume(corpora);
617dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert        }
6184572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood    }
6194572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood
620b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert    protected void getShortcutsForQuery(String query, Collection<Corpus> corporaToQuery,
621b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert            final Suggestions suggestions) {
622b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        ShortcutRepository shortcutRepo = getShortcutRepository();
623b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert        if (shortcutRepo == null) return;
624e15fe38f0142174d223bfda0cd87d1a749a85facMathew Inwood        if (query.length() == 0 && !getConfig().showShortcutsForZeroQuery()) {
625e15fe38f0142174d223bfda0cd87d1a749a85facMathew Inwood            return;
626e15fe38f0142174d223bfda0cd87d1a749a85facMathew Inwood        }
627b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert        Consumer<ShortcutCursor> consumer = Consumers.createAsyncCloseableConsumer(mHandler,
628b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert                new Consumer<ShortcutCursor>() {
629b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert            public boolean consume(ShortcutCursor shortcuts) {
630b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert                suggestions.setShortcuts(shortcuts);
631b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert                return true;
632b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert            }
633b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert        });
6348749e77dddec9e7984ee86a7be6f5ba4fce44362Bjorn Bringert        shortcutRepo.getShortcutsForQuery(query, corporaToQuery,
6358749e77dddec9e7984ee86a7be6f5ba4fce44362Bjorn Bringert                getSettings().allowWebSearchShortcuts(), consumer);
636b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    }
63711234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert
638dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert    public void updateSuggestions() {
6397f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert        if (DBG) Log.d(TAG, "updateSuggestions()");
6407f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert        final String query = CharMatcher.WHITESPACE.trimLeadingFrom(getQuery());
6414572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood        getQsbApplication().getSourceTaskExecutor().cancelPendingTasks();
6426859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        getCorporaToQuery(new Consumer<List<Corpus>>(){
6436859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            @Override
6446859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            public boolean consume(List<Corpus> corporaToQuery) {
6456859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert                updateSuggestions(query, corporaToQuery);
6466859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert                return true;
6476859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert            }
6486859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert        });
6496859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    }
650b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert
6516859aead3af0680b2c9dc326244aa89835c2c852Bjorn Bringert    protected void updateSuggestions(String query, List<Corpus> corporaToQuery) {
6527f5ff91319a8433abd92f3e3179158e38391e159Bjorn Bringert        if (DBG) Log.d(TAG, "updateSuggestions(\"" + query+"\"," + corporaToQuery + ")");
653b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        Suggestions suggestions = getSuggestionsProvider().getSuggestions(
654b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert                query, corporaToQuery);
655b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert        getShortcutsForQuery(query, corporaToQuery, suggestions);
656b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert
657b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        // Log start latency if this is the first suggestions update
658b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        gotSuggestions(suggestions);
659b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert
6605880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert        showSuggestions(suggestions);
6615880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert    }
6625880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert
6635880fdc4f6fef3c9b5b95a49a0f23c37c69f89d5Bjorn Bringert    protected void showSuggestions(Suggestions suggestions) {
6647010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        mSearchActivityView.setSuggestions(suggestions);
665185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert    }
666185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
667185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert    private class ClickHandler implements SuggestionClickListener {
668848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
6697010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public void onSuggestionQuickContactClicked(SuggestionsAdapter adapter, int position) {
6707010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            clickedQuickContact(adapter, position);
671848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
6723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
6737010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public void onSuggestionClicked(SuggestionsAdapter adapter, int position) {
6747010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            launchSuggestion(adapter, position);
675848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
676145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert
677fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert        public void onSuggestionRemoveFromHistoryClicked(SuggestionsAdapter adapter, int position) {
678fb8ce18922dae59db424fce906b5c113797fe81eBjorn Bringert            removeFromHistory(adapter, position);
679848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
6803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
6817010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert        public void onSuggestionQueryRefineClicked(SuggestionsAdapter adapter, int position) {
6827010c51b51c97fa43d7b24d2158ecbc1d064e0a6Bjorn Bringert            refineSuggestion(adapter, position);
6832617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert        }
684f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert    }
685f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert
686dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    private class CorpusSelectorDismissListener implements DialogInterface.OnDismissListener {
687dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        public void onDismiss(DialogInterface dialog) {
688dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            if (DBG) Log.d(TAG, "Corpus selector dismissed");
689dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert            clearStartedIntoCorpusSelectionDialog();
690dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert        }
691dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert    }
692dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert
69321bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    private class CorporaObserver extends DataSetObserver {
69421bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        @Override
69521bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        public void onChanged() {
69621bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert            setCorpus(getCorpusName());
697dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert            updateSuggestions();
69821bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        }
69921bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    }
70021bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert
7012607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood    public interface OnDestroyListener {
7022607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood        void onDestroyed();
7032607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood    }
7042607687d72deb8e06329597ab8bffcca9c746153Mathew Inwood
7053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert}
706