SearchActivity.java revision 535931433926d342c6277034cad91143ae28b72d
13e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/* 23e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Copyright (C) 2009 The Android Open Source Project 33e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 43e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); 53e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * you may not use this file except in compliance with the License. 63e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * You may obtain a copy of the License at 73e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 83e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0 93e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Unless required by applicable law or agreed to in writing, software 113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS, 123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * See the License for the specific language governing permissions and 143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * limitations under the License. 153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpackage com.android.quicksearchbox; 183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 193f71a11f8858b9164ca83e8d2f558dd8a8a5e2deBjorn Bringertimport com.android.common.Search; 20c5a3ecb62318a6be1d1a626a36b52829e989f740Bjorn Bringertimport com.android.quicksearchbox.ui.CorpusViewFactory; 21185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionClickListener; 227b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionSelectionListener; 23185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionsAdapter; 24883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringertimport com.android.quicksearchbox.ui.SuggestionsFooter; 25185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionsView; 26185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.app.Activity; 282617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringertimport android.app.Dialog; 293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.app.SearchManager; 303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.Intent; 313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.database.DataSetObserver; 323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.graphics.drawable.Animatable; 33d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinneyimport android.graphics.drawable.Drawable; 34fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.net.Uri; 353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.os.Bundle; 36ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringertimport android.os.SystemClock; 373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.Editable; 383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.TextUtils; 393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.TextWatcher; 403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.util.Log; 413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.KeyEvent; 423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.Menu; 433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.View; 44883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringertimport android.view.ViewGroup; 453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.View.OnFocusChangeListener; 463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.inputmethod.InputMethodManager; 473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.widget.EditText; 483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.widget.ImageButton; 493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 50ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringertimport java.util.ArrayList; 51ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert 523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/** 533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * The main activity for Quick Search Box. Shows the search UI. 543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpublic class SearchActivity extends Activity { 573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private static final boolean DBG = true; 590484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private static final String TAG = "QSB.SearchActivity"; 603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 61fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private static final String SCHEME_CORPUS = "qsb.corpus"; 62fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 63fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public static final String INTENT_ACTION_QSB_AND_SELECT_CORPUS 64fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert = "com.android.quicksearchbox.action.QSB_AND_SELECT_CORPUS"; 653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 66c15f386b167efb3f7559f2f7ee362497040b7fe6Bjorn Bringert // The string used for privateImeOptions to identify to the IME that it should not show 67c15f386b167efb3f7559f2f7ee362497040b7fe6Bjorn Bringert // a microphone button since one already exists in the search dialog. 68c15f386b167efb3f7559f2f7ee362497040b7fe6Bjorn Bringert // TODO: This should move to android-common or something. 69c15f386b167efb3f7559f2f7ee362497040b7fe6Bjorn Bringert private static final String IME_OPTION_NO_MICROPHONE = "nm"; 70c15f386b167efb3f7559f2f7ee362497040b7fe6Bjorn Bringert 719ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // Keys for the saved instance state. 72fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private static final String INSTANCE_KEY_CORPUS = "corpus"; 739ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert private static final String INSTANCE_KEY_USER_QUERY = "query"; 74713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 752617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert // Dialog IDs 76fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private static final int CORPUS_SELECTION_DIALOG = 0; 772617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 78ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert // Timestamp for last onCreate()/onNewIntent() call, as returned by SystemClock.uptimeMillis(). 79ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert private long mStartTime; 80ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert // Whether QSB is starting. True between the calls to onCreate()/onNewIntent() and onResume(). 81ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert private boolean mStarting; 82ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert // True if the user has taken some action, e.g. launching a search, voice search, 83ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert // or suggestions, since QSB was last started. 84ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert private boolean mTookAction; 85ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert 86185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert protected SuggestionsAdapter mSuggestionsAdapter; 87185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected EditText mQueryTextView; 89e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert // True if the query was empty on the previous call to updateQuery() 90e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert protected boolean mQueryWasEmpty = true; 913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected SuggestionsView mSuggestionsView; 93883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert protected SuggestionsFooter mSuggestionsFooter; 943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected ImageButton mSearchGoButton; 963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected ImageButton mVoiceSearchButton; 97a576b1abd602c08dcf0d470facc43fac0243b07cBjorn Bringert protected ImageButton mCorpusIndicator; 983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private Launcher mLauncher; 1003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 101fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private Corpus mCorpus; 1022617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert private Bundle mAppSearchData; 103713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private boolean mUpdateSuggestions; 104713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private String mUserQuery; 105713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private boolean mSelectAll; 1063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** Called when the activity is first created. */ 1083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 1093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onCreate(Bundle savedInstanceState) { 110ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert recordStartTime(); 1113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "onCreate()"); 1123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onCreate(savedInstanceState); 113713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 114e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert setContentView(R.layout.search_activity); 1153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 116816804b67619af133860a1e28e92f58bc642260dBjorn Bringert mSuggestionsAdapter = getQsbApplication().createSuggestionsAdapter(); 117185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 1183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQueryTextView = (EditText) findViewById(R.id.search_src_text); 1193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSuggestionsView = (SuggestionsView) findViewById(R.id.suggestions); 120782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mSuggestionsView.setSuggestionClickListener(new ClickHandler()); 1217b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert mSuggestionsView.setSuggestionSelectionListener(new SelectionHandler()); 122782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mSuggestionsView.setInteractionListener(new InputMethodCloser()); 123713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSuggestionsView.setOnKeyListener(new SuggestionsViewKeyListener()); 1247b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert mSuggestionsView.setOnFocusChangeListener(new SuggestListFocusListener()); 1253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 126883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert mSuggestionsFooter = getQsbApplication().createSuggestionsFooter(); 127dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert ViewGroup footerFrame = (ViewGroup) findViewById(R.id.footer); 128dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert mSuggestionsFooter.addToContainer(footerFrame); 129883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert 1303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSearchGoButton = (ImageButton) findViewById(R.id.search_go_btn); 1313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mVoiceSearchButton = (ImageButton) findViewById(R.id.search_voice_btn); 132a576b1abd602c08dcf0d470facc43fac0243b07cBjorn Bringert mCorpusIndicator = (ImageButton) findViewById(R.id.corpus_indicator); 1333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1349ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mLauncher = new Launcher(this); 1353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 136782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mQueryTextView.addTextChangedListener(new SearchTextWatcher()); 137782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mQueryTextView.setOnKeyListener(new QueryTextViewKeyListener()); 1387b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert mQueryTextView.setOnFocusChangeListener(new QueryTextViewFocusListener()); 139782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 140fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert mCorpusIndicator.setOnClickListener(new CorpusIndicatorClickListener()); 1412617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 142782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mSearchGoButton.setOnClickListener(new SearchGoButtonClickListener()); 143782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 144782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mVoiceSearchButton.setOnClickListener(new VoiceSearchButtonClickListener()); 1457be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert 1467be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert ButtonsKeyListener buttonsKeyListener = new ButtonsKeyListener(); 1477be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert mSearchGoButton.setOnKeyListener(buttonsKeyListener); 1487be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert mVoiceSearchButton.setOnKeyListener(buttonsKeyListener); 149fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert mCorpusIndicator.setOnKeyListener(buttonsKeyListener); 150713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 1519ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mUpdateSuggestions = true; 1529ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert 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. 161713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSuggestionsView.setAdapter(mSuggestionsAdapter); 162dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert mSuggestionsFooter.setAdapter(mSuggestionsAdapter); 1639ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert } 164713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 1659ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert @Override 1669ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert protected void onNewIntent(Intent intent) { 167ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert recordStartTime(); 1689ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setIntent(intent); 1699ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setupFromIntent(intent); 1709ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert } 1719ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert 172ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert private void recordStartTime() { 173ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert mStartTime = SystemClock.uptimeMillis(); 174ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert mStarting = true; 175ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert mTookAction = false; 176ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert } 177ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert 1789ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert protected void restoreInstanceState(Bundle savedInstanceState) { 1799ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert if (savedInstanceState == null) return; 180fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert String corpusName = savedInstanceState.getString(INSTANCE_KEY_CORPUS); 1819ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert String query = savedInstanceState.getString(INSTANCE_KEY_USER_QUERY); 182fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert setCorpus(getCorpus(corpusName)); 1839ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setUserQuery(query); 184713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 185713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 186713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert @Override 1879ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert protected void onSaveInstanceState(Bundle outState) { 1889ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert super.onSaveInstanceState(outState); 1899ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // We don't save appSearchData, since we always get the value 1909ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // from the intent and the user can't change it. 191fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 192fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert String corpusName = mCorpus == null ? null : mCorpus.getName(); 193fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert outState.putString(INSTANCE_KEY_CORPUS, corpusName); 1949ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert outState.putString(INSTANCE_KEY_USER_QUERY, mUserQuery); 195713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 196713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 197713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private void setupFromIntent(Intent intent) { 198713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert if (DBG) Log.d(TAG, "setupFromIntent(" + intent.toUri(0) + ")"); 199fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert Corpus corpus = getCorpusFromUri(intent.getData()); 2002617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert String query = intent.getStringExtra(SearchManager.QUERY); 2012617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert Bundle appSearchData = intent.getBundleExtra(SearchManager.APP_DATA); 2022617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 203fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert setCorpus(corpus); 2042617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert setUserQuery(query); 205154017089860da89ec020ed37e502d194253cc67Bjorn Bringert mSelectAll = intent.getBooleanExtra(SearchManager.EXTRA_SELECT_QUERY, false); 206c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert mAppSearchData = appSearchData; 2072617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 208fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (INTENT_ACTION_QSB_AND_SELECT_CORPUS.equals(intent.getAction())) { 20941fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert showCorpusSelectionDialog(); 2102617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 2119ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert } 2129ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert 213fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public static Uri getCorpusUri(Corpus corpus) { 214fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (corpus == null) return null; 215fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return new Uri.Builder() 216fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert .scheme(SCHEME_CORPUS) 217fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert .authority(corpus.getName()) 218fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert .build(); 219fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 220fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 221fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private Corpus getCorpusFromUri(Uri uri) { 222fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (uri == null) return null; 223fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (!SCHEME_CORPUS.equals(uri.getScheme())) return null; 224fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert String name = uri.getAuthority(); 225fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return getCorpus(name); 226fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 227fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 228fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private Corpus getCorpus(String sourceName) { 2290ccab5903ba2c64ec4cdd33dbcea91b1e279d556Bjorn Bringert if (sourceName == null) return null; 230fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert Corpus corpus = getCorpora().getCorpus(sourceName); 231fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (corpus == null) { 232fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert Log.w(TAG, "Unknown corpus " + sourceName); 2339ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert return null; 234713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 235fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return corpus; 236713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 237713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 238fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private void setCorpus(Corpus corpus) { 239fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (DBG) Log.d(TAG, "setCorpus(" + corpus + ")"); 240fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert mCorpus = corpus; 2419ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert Drawable sourceIcon; 242fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (corpus == null) { 243c5a3ecb62318a6be1d1a626a36b52829e989f740Bjorn Bringert sourceIcon = getCorpusViewFactory().getGlobalSearchIcon(); 244713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } else { 245fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert sourceIcon = corpus.getCorpusIcon(); 246713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 247fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert mSuggestionsAdapter.setCorpus(corpus); 248a576b1abd602c08dcf0d470facc43fac0243b07cBjorn Bringert mCorpusIndicator.setImageDrawable(sourceIcon); 2493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 250e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert updateVoiceSearchButton(getQuery().length() == 0); 2510484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 2520484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 2533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private QsbApplication getQsbApplication() { 2543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return (QsbApplication) getApplication(); 2553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 257fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private Corpora getCorpora() { 258fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return getQsbApplication().getCorpora(); 259fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 260fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 261fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private CorpusRanker getCorpusRanker() { 262fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return getQsbApplication().getCorpusRanker(); 263713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 264713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 2653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private ShortcutRepository getShortcutRepository() { 2663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getQsbApplication().getShortcutRepository(); 2673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 269ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert private SuggestionsProvider getSuggestionsProvider() { 270fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return getQsbApplication().getSuggestionsProvider(mCorpus); 2713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 273c5a3ecb62318a6be1d1a626a36b52829e989f740Bjorn Bringert private CorpusViewFactory getCorpusViewFactory() { 274c5a3ecb62318a6be1d1a626a36b52829e989f740Bjorn Bringert return getQsbApplication().getCorpusViewFactory(); 275185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert } 276185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 277ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert private Logger getLogger() { 278ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert return getQsbApplication().getLogger(); 279ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert } 280ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert 2813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 2823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onDestroy() { 2833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "onDestroy()"); 2843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onDestroy(); 285dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert mSuggestionsFooter.setAdapter(null); 286185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsView.setAdapter(null); // closes mSuggestionsAdapter 2873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 2903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onStop() { 2919ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert if (DBG) Log.d(TAG, "onStop()"); 2929ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // Close all open suggestion cursors. The query will be redone in onResume() 2933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // if we come back to this activity. 294185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsAdapter.setSuggestions(null); 29594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney getQsbApplication().getShortcutRefresher().reset(); 2963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onStop(); 2973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 300b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert protected void onResume() { 3019ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert if (DBG) Log.d(TAG, "onResume()"); 302b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert super.onResume(); 3039ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setQuery(mUserQuery, mSelectAll); 3049ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // Only select everything the first time after creating the activity. 3059ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mSelectAll = false; 3069ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert updateSuggestions(mUserQuery); 307b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert mQueryTextView.requestFocus(); 308ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert if (mStarting) { 309ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert mStarting = false; 310ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert // Start up latency should not exceed 2^31 ms (~ 25 days). Note that 311ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert // SystemClock.uptimeMillis() does not advance during deep sleep. 312ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert int latency = (int) (SystemClock.uptimeMillis() - mStartTime); 3133f71a11f8858b9164ca83e8d2f558dd8a8a5e2deBjorn Bringert String source = getIntent().getStringExtra(Search.SOURCE); 314fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert getLogger().logStart(latency, source, mCorpus, 315fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert getSuggestionsProvider().getOrderedCorpora()); 316ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert } 317b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert } 318b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert 319b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert @Override 3203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean onCreateOptionsMenu(Menu menu) { 3213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onCreateOptionsMenu(menu); 32226d85260316193a1aeff5d407d4f32f5297be012Bjorn Bringert SearchSettings.addSearchSettingsMenuItem(this, menu); 3233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return true; 3243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3269ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert /** 3279ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert * Sets the query as typed by the user. Does not update the suggestions 3289ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert * or the text in the query box. 3299ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert */ 3309ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert protected void setUserQuery(String userQuery) { 3319ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert if (userQuery == null) userQuery = ""; 3329ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mUserQuery = userQuery; 3339ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert } 3349ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert 335713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert protected String getQuery() { 3363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert CharSequence q = mQueryTextView.getText(); 3373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return q == null ? "" : q.toString(); 3383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Restores the query entered by the user. 3423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 3433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void restoreUserQuery() { 3443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Restoring query to '" + mUserQuery + "'"); 3453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert setQuery(mUserQuery, false); 3463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Sets the text in the query box. Does not update the suggestions, 3503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * and does not change the saved user-entered query. 3513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * {@link #restoreUserQuery()} will restore the query to the last 3523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * user-entered query. 3533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 3543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void setQuery(String query, boolean selectAll) { 3553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mUpdateSuggestions = false; 3563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQueryTextView.setText(query); 3573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert setTextSelection(selectAll); 3583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mUpdateSuggestions = true; 3593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Sets the text selection in the query text view. 3633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 3643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * @param selectAll If {@code true}, selects the entire query. 3653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * If {@false}, no characters are selected, and the cursor is placed 3663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * at the end of the query. 3673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 3683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void setTextSelection(boolean selectAll) { 3693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (selectAll) { 3703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQueryTextView.setSelection(0, mQueryTextView.length()); 3713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else { 3723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQueryTextView.setSelection(mQueryTextView.length()); 3733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 376e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert private void updateQueryTextView(boolean queryEmpty) { 377e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert if (queryEmpty) { 378e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryTextView.setBackgroundResource(R.drawable.textfield_search_empty); 379e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryTextView.setCompoundDrawablesWithIntrinsicBounds( 380e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert R.drawable.placeholder_google, 0, 0, 0); 381e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryTextView.setCursorVisible(false); 382e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } else { 383e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryTextView.setBackgroundResource(R.drawable.textfield_search); 384e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); 385e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryTextView.setCursorVisible(true); 386e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 387e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 388e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert 389e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert private void updateSearchGoButton(boolean queryEmpty) { 390e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert if (queryEmpty) { 391e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mSearchGoButton.setVisibility(View.GONE); 392e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } else { 393e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mSearchGoButton.setVisibility(View.VISIBLE); 394e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 395e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 396e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert 397e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert protected void updateVoiceSearchButton(boolean queryEmpty) { 398c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert if (queryEmpty && mLauncher.shouldShowVoiceSearch(mCorpus)) { 399e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mVoiceSearchButton.setVisibility(View.VISIBLE); 400e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryTextView.setPrivateImeOptions(IME_OPTION_NO_MICROPHONE); 401e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } else { 402e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mVoiceSearchButton.setVisibility(View.GONE); 403e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryTextView.setPrivateImeOptions(null); 404e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 405e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 406e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert 40741fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert protected void showCorpusSelectionDialog() { 408fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert showDialog(CORPUS_SELECTION_DIALOG); 4092617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4102617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 41141fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert protected void dismissCorpusSelectionDialog() { 41241fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert dismissDialog(CORPUS_SELECTION_DIALOG); 41341fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert } 4142617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 4152617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert @Override 4162617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert protected Dialog onCreateDialog(int id, Bundle args) { 4172617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert switch (id) { 418fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert case CORPUS_SELECTION_DIALOG: 419fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return createCorpusSelectionDialog(); 4202617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert default: 4212617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert throw new IllegalArgumentException("Unknown dialog: " + id); 4222617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4232617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4242617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 4252617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert @Override 4262617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert protected void onPrepareDialog(int id, Dialog dialog, Bundle args) { 427c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert super.onPrepareDialog(id, dialog, args); 4282617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert switch (id) { 429fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert case CORPUS_SELECTION_DIALOG: 430fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert prepareCorpusSelectionDialog((CorpusSelectionDialog) dialog); 4312617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert break; 4322617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert default: 4332617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert throw new IllegalArgumentException("Unknown dialog: " + id); 4342617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4352617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4362617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 437fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected CorpusSelectionDialog createCorpusSelectionDialog() { 438c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert return new CorpusSelectionDialog(this); 4392617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4402617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 441fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected void prepareCorpusSelectionDialog(CorpusSelectionDialog dialog) { 442fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert dialog.setCorpus(mCorpus); 4432617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert dialog.setQuery(getQuery()); 4442617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert dialog.setAppData(mAppSearchData); 4452617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4462617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 447ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert protected void onSearchClicked(int method) { 4483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String query = getQuery(); 4493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Search clicked, query=" + query); 450535931433926d342c6277034cad91143ae28b72dBjorn Bringert Corpus searchCorpus = mLauncher.getSearchCorpus(getCorpora(), mCorpus); 451c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert if (searchCorpus == null) return; 452c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 453ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert mTookAction = true; 454c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 455c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Log search start 456fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert getLogger().logSearch(mCorpus, method, query.length()); 457c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 458c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Create shortcut 459c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert SuggestionData searchShortcut = searchCorpus.createSearchShortcut(query); 460c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert if (searchShortcut != null) { 461c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert DataSuggestionCursor cursor = new DataSuggestionCursor(query); 462c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert cursor.add(searchShortcut); 463c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert getShortcutRepository().reportClick(cursor, 0); 464c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert } 465c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 466c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Start search 467c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert Intent intent = searchCorpus.createSearchIntent(query, mAppSearchData); 468c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert mLauncher.launchIntent(intent); 4693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onVoiceSearchClicked() { 4723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Voice Search clicked"); 473535931433926d342c6277034cad91143ae28b72dBjorn Bringert Corpus searchCorpus = mLauncher.getSearchCorpus(getCorpora(), mCorpus); 474c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert if (searchCorpus == null) return; 475c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 476535931433926d342c6277034cad91143ae28b72dBjorn Bringert mTookAction = true; 477535931433926d342c6277034cad91143ae28b72dBjorn Bringert 478c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Log voice search start 479c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert getLogger().logVoiceSearch(searchCorpus); 480ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert 481c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Start voice search 482c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert Intent intent = searchCorpus.createVoiceSearchIntent(mAppSearchData); 483c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert mLauncher.launchIntent(intent); 484c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert } 485c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 486fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected SuggestionCursor getSuggestions() { 487fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return mSuggestionsAdapter.getCurrentSuggestions(); 488782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 489782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 490fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected boolean launchSuggestion(int position) { 491fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (DBG) Log.d(TAG, "Launching suggestion " + position); 492ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert mTookAction = true; 493fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert SuggestionCursor suggestions = getSuggestions(); 494c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 495c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Log suggestion click 496ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert // TODO: This should be just the queried sources, but currently 497ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert // all sources are queried 498fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert ArrayList<Corpus> corpora = getCorpusRanker().rankCorpora(getCorpora().getEnabledCorpora()); 499fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert getLogger().logSuggestionClick(position, suggestions, corpora); 500ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert 501c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Create shortcut 502fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert getShortcutRepository().reportClick(suggestions, position); 503c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 504c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Launch intent 505c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert Intent intent = mLauncher.getSuggestionIntent(suggestions, position, mAppSearchData); 506c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert mLauncher.launchIntent(intent); 507c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 5083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return true; 5093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 511fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected boolean onSuggestionLongClicked(int position) { 512fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (DBG) Log.d(TAG, "Long clicked on suggestion " + position); 5133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return false; 5143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 516fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected boolean onSuggestionKeyDown(int position, int keyCode, KeyEvent event) { 517782dd228e78e9294692d639597f96c26283968bbBjorn Bringert // Treat enter or search as a click 518782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH) { 519fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return launchSuggestion(position); 520782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 521782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 5227b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (keyCode == KeyEvent.KEYCODE_DPAD_UP 5237b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert && mSuggestionsView.getSelectedItemPosition() == 0) { 5247b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert // Moved up from the top suggestion, restore the user query and focus query box 5257b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (DBG) Log.d(TAG, "Up and out"); 5267b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert restoreUserQuery(); 5277b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert return false; // let the framework handle the move 5287b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 5297b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert 5307b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT 5317b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) { 5327b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert // Moved left / right from a suggestion, keep current query, move 5337b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert // focus to query box, and move cursor to far left / right 5347b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (DBG) Log.d(TAG, "Left/right on a suggestion"); 5357b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert int cursorPos = (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) ? 0 : mQueryTextView.length(); 5367b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert mQueryTextView.setSelection(cursorPos); 5377b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert mQueryTextView.requestFocus(); 5387b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert // TODO: should we modify the list selection? 5397b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert return true; 5407b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 5417b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert 542782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return false; 543782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 544782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 5453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onSourceSelected() { 5463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "No suggestion selected"); 5473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert restoreUserQuery(); 5483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 550782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected int getSelectedPosition() { 551782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return mSuggestionsView.getSelectedPosition(); 552782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 553782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 5543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 5553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Hides the input method. 5563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 5573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void hideInputMethod() { 5583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); 5593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (imm != null) { 5603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert imm.hideSoftInputFromWindow(mQueryTextView.getWindowToken(), 0); 5613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5647b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert protected void showInputMethodForQuery() { 5657b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); 5667b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (imm != null) { 5676c8a8cb66ccf57347c7aed4260132d342b242b0fBjorn Bringert imm.showSoftInput(mQueryTextView, InputMethodManager.SHOW_IMPLICIT); 5687b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 5697b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 5707b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert 5713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 5723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Hides the input method when the suggestions get focus. 5733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 5743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class SuggestListFocusListener implements OnFocusChangeListener { 5753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onFocusChange(View v, boolean focused) { 5767b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (DBG) Log.d(TAG, "Suggestions focus change, now: " + focused); 5777b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (focused) { 5787b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert // The suggestions list got focus, hide the input method 5797b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert hideInputMethod(); 5807b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 5817b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 5827b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 5837b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert 5847b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert private class QueryTextViewFocusListener implements OnFocusChangeListener { 5857b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert public void onFocusChange(View v, boolean focused) { 5867b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (DBG) Log.d(TAG, "Query focus change, now: " + focused); 5877b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (focused) { 5887b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert // The query box got focus, show the input method if the 5897b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert // query box got focus? 5907b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert showInputMethodForQuery(); 5913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void startSearchProgress() { 596e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert // TODO: Do we need a progress indicator? 5973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void stopSearchProgress() { 600d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney Drawable animation = mSearchGoButton.getDrawable(); 601d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney if (animation instanceof Animatable) { 602d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney // TODO: Is this needed, or is it done automatically when the 603d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney // animation is removed? 604d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney ((Animatable) animation).stop(); 605d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney } 6063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSearchGoButton.setImageResource(R.drawable.ic_btn_search); 6073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void updateSuggestions(String query) { 6103d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney query = ltrim(query); 6113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert LatencyTracker latency = new LatencyTracker(TAG); 612ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert Suggestions suggestions = getSuggestionsProvider().getSuggestions(query); 6133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert latency.addEvent("getSuggestions_done"); 6143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (!suggestions.isDone()) { 6153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert suggestions.registerDataSetObserver(new ProgressUpdater(suggestions)); 6163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert startSearchProgress(); 617d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney } else { 618d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney stopSearchProgress(); 6193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 620185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsAdapter.setSuggestions(suggestions); 6213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert latency.addEvent("shortcuts_shown"); 6223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert long userVisibleLatency = latency.getUserVisibleLatency(); 6233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) { 6243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.d(TAG, "User visible latency (shortcuts): " + userVisibleLatency + " ms."); 6253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6287be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert private boolean forwardKeyToQueryTextView(int keyCode, KeyEvent event) { 6297be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert if (!event.isSystem() && !isDpadKey(keyCode)) { 6307be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert if (DBG) Log.d(TAG, "Forwarding key to query box: " + event); 6317be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert if (mQueryTextView.requestFocus()) { 6327be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return mQueryTextView.dispatchKeyEvent(event); 6337be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert } 6347be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert } 6357be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return false; 6367be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert } 6377be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert 6387be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert private boolean isDpadKey(int keyCode) { 6397be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert switch (keyCode) { 6407be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert case KeyEvent.KEYCODE_DPAD_UP: 6417be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert case KeyEvent.KEYCODE_DPAD_DOWN: 6427be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert case KeyEvent.KEYCODE_DPAD_LEFT: 6437be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert case KeyEvent.KEYCODE_DPAD_RIGHT: 6447be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert case KeyEvent.KEYCODE_DPAD_CENTER: 6457be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return true; 6467be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert default: 6477be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return false; 6487be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert } 6497be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert } 6507be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert 6513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 6523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Filters the suggestions list when the search text changes. 6533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 6543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class SearchTextWatcher implements TextWatcher { 6553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void afterTextChanged(Editable s) { 656e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert boolean empty = s.length() == 0; 657e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert if (empty != mQueryWasEmpty) { 658e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryWasEmpty = empty; 659e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert updateQueryTextView(empty); 660e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert updateSearchGoButton(empty); 661e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert updateVoiceSearchButton(empty); 662e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 6633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mUpdateSuggestions) { 6643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String query = s == null ? "" : s.toString(); 6659ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setUserQuery(query); 6663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert updateSuggestions(query); 6673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void beforeTextChanged(CharSequence s, int start, int count, int after) { 6713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onTextChanged(CharSequence s, int start, int before, int count) { 6743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 6783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Handles non-text keys in the query text view. 6793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 6803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class QueryTextViewKeyListener implements View.OnKeyListener { 6813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean onKey(View view, int keyCode, KeyEvent event) { 6823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Handle IME search action key 6833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) { 684ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert onSearchClicked(Logger.SEARCH_METHOD_KEYBOARD); 6853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return false; 6873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 690782dd228e78e9294692d639597f96c26283968bbBjorn Bringert /** 691782dd228e78e9294692d639597f96c26283968bbBjorn Bringert * Handles key events on the search and voice search buttons, 692782dd228e78e9294692d639597f96c26283968bbBjorn Bringert * by refocusing to EditText. 693782dd228e78e9294692d639597f96c26283968bbBjorn Bringert */ 694782dd228e78e9294692d639597f96c26283968bbBjorn Bringert private class ButtonsKeyListener implements View.OnKeyListener { 695782dd228e78e9294692d639597f96c26283968bbBjorn Bringert public boolean onKey(View v, int keyCode, KeyEvent event) { 6967be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return forwardKeyToQueryTextView(keyCode, event); 697782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 698782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 699782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 700782dd228e78e9294692d639597f96c26283968bbBjorn Bringert /** 701782dd228e78e9294692d639597f96c26283968bbBjorn Bringert * Handles key events on the suggestions list view. 702782dd228e78e9294692d639597f96c26283968bbBjorn Bringert */ 703713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private class SuggestionsViewKeyListener implements View.OnKeyListener { 704782dd228e78e9294692d639597f96c26283968bbBjorn Bringert public boolean onKey(View v, int keyCode, KeyEvent event) { 705782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (event.getAction() == KeyEvent.ACTION_DOWN) { 706fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert int position = getSelectedPosition(); 707fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (onSuggestionKeyDown(position, keyCode, event)) { 7087be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return true; 709782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 710782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 7117be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return forwardKeyToQueryTextView(keyCode, event); 712782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 713782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 714782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 715185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert private class InputMethodCloser implements SuggestionsView.InteractionListener { 716185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert public void onInteraction() { 717185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert hideInputMethod(); 718185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert } 719185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert } 720185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 721185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert private class ClickHandler implements SuggestionClickListener { 722fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public void onSuggestionClicked(int position) { 723fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert launchSuggestion(position); 7243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 726fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public boolean onSuggestionLongClicked(int position) { 727fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return SearchActivity.this.onSuggestionLongClicked(position); 728713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 7293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7317b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert private class SelectionHandler implements SuggestionSelectionListener { 732fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public void onSuggestionSelected(int position) { 733fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert SuggestionCursor suggestions = getSuggestions(); 734fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert suggestions.moveTo(position); 735fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert String displayQuery = suggestions.getSuggestionDisplayQuery(); 736fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (TextUtils.isEmpty(displayQuery)) { 737fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert restoreUserQuery(); 738fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } else { 739fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert setQuery(displayQuery, false); 740fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 741fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 742fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 743fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public void onNothingSelected() { 744fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // This happens when a suggestion has been selected with the 745fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // dpad / trackball and then a different UI element is touched. 746fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // Do nothing, since we want to keep the query of the selection 747fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // in the search box. 7487b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 7497b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 7507b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert 7513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 7522617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert * Listens for clicks on the source selector. 7533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 7543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class SearchGoButtonClickListener implements View.OnClickListener { 7553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onClick(View view) { 756ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert onSearchClicked(Logger.SEARCH_METHOD_BUTTON); 7573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 7612617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert * Listens for clicks on the search button. 7622617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert */ 763fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private class CorpusIndicatorClickListener implements View.OnClickListener { 7642617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert public void onClick(View view) { 76541fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert showCorpusSelectionDialog(); 7662617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 7672617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 7682617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 7692617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert /** 7703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Listens for clicks on the voice search button. 7713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 7723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class VoiceSearchButtonClickListener implements View.OnClickListener { 7733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onClick(View view) { 7743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert onVoiceSearchClicked(); 7753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 7793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Updates the progress bar when the suggestions adapter changes its progress. 7803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 7813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class ProgressUpdater extends DataSetObserver { 7823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final Suggestions mSuggestions; 7833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public ProgressUpdater(Suggestions suggestions) { 7853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSuggestions = suggestions; 7863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 7893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onChanged() { 7903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mSuggestions.isDone()) { 7913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert stopSearchProgress(); 7923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 795713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 7963d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney private static String ltrim(String text) { 7973d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney int start = 0; 7983d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney int length = text.length(); 7993d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney while (start < length && Character.isWhitespace(text.charAt(start))) { 8003d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney start++; 8013d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney } 8023d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney return start > 0 ? text.substring(start, length) : text; 8033d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney } 8043d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney 8053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert} 806