SearchActivity.java revision eba26da75665ac3b9a411e74267395f332ff851a
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 2505691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert updateUi(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) { 3705691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert mQueryTextView.selectAll(); 3713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else { 3723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQueryTextView.setSelection(mQueryTextView.length()); 3733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3765691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert private void updateUi(boolean queryEmpty) { 3775691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert updateQueryTextView(queryEmpty); 3785691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert updateSearchGoButton(queryEmpty); 3795691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert updateVoiceSearchButton(queryEmpty); 3805691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert } 3815691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert 382e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert private void updateQueryTextView(boolean queryEmpty) { 383e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert if (queryEmpty) { 3845691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert if (mCorpus == null || mCorpus.isWebCorpus()) { 3855691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert mQueryTextView.setBackgroundResource(R.drawable.textfield_search_empty_google); 3865691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert mQueryTextView.setHint(null); 3875691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert } else { 3885691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert mQueryTextView.setBackgroundResource(R.drawable.textfield_search_empty); 3895691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert mQueryTextView.setHint(mCorpus.getHint()); 3905691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert } 391e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } else { 392e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryTextView.setBackgroundResource(R.drawable.textfield_search); 393e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 394e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 395e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert 396e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert private void updateSearchGoButton(boolean queryEmpty) { 397e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert if (queryEmpty) { 398e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mSearchGoButton.setVisibility(View.GONE); 399e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } else { 400e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mSearchGoButton.setVisibility(View.VISIBLE); 401e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 402e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 403e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert 404e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert protected void updateVoiceSearchButton(boolean queryEmpty) { 405c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert if (queryEmpty && mLauncher.shouldShowVoiceSearch(mCorpus)) { 406e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mVoiceSearchButton.setVisibility(View.VISIBLE); 407e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryTextView.setPrivateImeOptions(IME_OPTION_NO_MICROPHONE); 408e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } else { 409e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mVoiceSearchButton.setVisibility(View.GONE); 410e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryTextView.setPrivateImeOptions(null); 411e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 412e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 413e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert 41441fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert protected void showCorpusSelectionDialog() { 415fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert showDialog(CORPUS_SELECTION_DIALOG); 4162617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4172617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 41841fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert protected void dismissCorpusSelectionDialog() { 41941fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert dismissDialog(CORPUS_SELECTION_DIALOG); 42041fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert } 4212617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 4222617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert @Override 4232617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert protected Dialog onCreateDialog(int id, Bundle args) { 4242617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert switch (id) { 425fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert case CORPUS_SELECTION_DIALOG: 426fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return createCorpusSelectionDialog(); 4272617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert default: 4282617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert throw new IllegalArgumentException("Unknown dialog: " + id); 4292617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4302617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4312617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 4322617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert @Override 4332617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert protected void onPrepareDialog(int id, Dialog dialog, Bundle args) { 434c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert super.onPrepareDialog(id, dialog, args); 4352617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert switch (id) { 436fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert case CORPUS_SELECTION_DIALOG: 437fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert prepareCorpusSelectionDialog((CorpusSelectionDialog) dialog); 4382617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert break; 4392617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert default: 4402617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert throw new IllegalArgumentException("Unknown dialog: " + id); 4412617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4422617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4432617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 444fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected CorpusSelectionDialog createCorpusSelectionDialog() { 445c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert return new CorpusSelectionDialog(this); 4462617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4472617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 448fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected void prepareCorpusSelectionDialog(CorpusSelectionDialog dialog) { 449fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert dialog.setCorpus(mCorpus); 4502617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert dialog.setQuery(getQuery()); 4512617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert dialog.setAppData(mAppSearchData); 4522617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4532617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 454ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert protected void onSearchClicked(int method) { 4553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String query = getQuery(); 4563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Search clicked, query=" + query); 457eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert 458eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert // Don't do empty queries 459eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert if (TextUtils.getTrimmedLength(query) == 0) return; 460eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert 461535931433926d342c6277034cad91143ae28b72dBjorn Bringert Corpus searchCorpus = mLauncher.getSearchCorpus(getCorpora(), mCorpus); 462c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert if (searchCorpus == null) return; 463c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 464ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert mTookAction = true; 465c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 466c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Log search start 467fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert getLogger().logSearch(mCorpus, method, query.length()); 468c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 469c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Create shortcut 470c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert SuggestionData searchShortcut = searchCorpus.createSearchShortcut(query); 471c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert if (searchShortcut != null) { 472c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert DataSuggestionCursor cursor = new DataSuggestionCursor(query); 473c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert cursor.add(searchShortcut); 474c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert getShortcutRepository().reportClick(cursor, 0); 475c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert } 476c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 477c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Start search 478c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert Intent intent = searchCorpus.createSearchIntent(query, mAppSearchData); 479c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert mLauncher.launchIntent(intent); 4803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onVoiceSearchClicked() { 4833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Voice Search clicked"); 484535931433926d342c6277034cad91143ae28b72dBjorn Bringert Corpus searchCorpus = mLauncher.getSearchCorpus(getCorpora(), mCorpus); 485c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert if (searchCorpus == null) return; 486c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 487535931433926d342c6277034cad91143ae28b72dBjorn Bringert mTookAction = true; 488535931433926d342c6277034cad91143ae28b72dBjorn Bringert 489c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Log voice search start 490c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert getLogger().logVoiceSearch(searchCorpus); 491ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert 492c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Start voice search 493c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert Intent intent = searchCorpus.createVoiceSearchIntent(mAppSearchData); 494c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert mLauncher.launchIntent(intent); 495c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert } 496c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 497fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected SuggestionCursor getSuggestions() { 498fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return mSuggestionsAdapter.getCurrentSuggestions(); 499782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 500782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 501fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected boolean launchSuggestion(int position) { 502fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (DBG) Log.d(TAG, "Launching suggestion " + position); 503ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert mTookAction = true; 504fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert SuggestionCursor suggestions = getSuggestions(); 505c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 506c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Log suggestion click 507ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert // TODO: This should be just the queried sources, but currently 508ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert // all sources are queried 509fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert ArrayList<Corpus> corpora = getCorpusRanker().rankCorpora(getCorpora().getEnabledCorpora()); 510fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert getLogger().logSuggestionClick(position, suggestions, corpora); 511ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert 512c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Create shortcut 513fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert getShortcutRepository().reportClick(suggestions, position); 514c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 515c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Launch intent 516c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert Intent intent = mLauncher.getSuggestionIntent(suggestions, position, mAppSearchData); 517c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert mLauncher.launchIntent(intent); 518c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 5193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return true; 5203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 522fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected boolean onSuggestionLongClicked(int position) { 523fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (DBG) Log.d(TAG, "Long clicked on suggestion " + position); 5243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return false; 5253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 527fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected boolean onSuggestionKeyDown(int position, int keyCode, KeyEvent event) { 528782dd228e78e9294692d639597f96c26283968bbBjorn Bringert // Treat enter or search as a click 529782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH) { 530fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return launchSuggestion(position); 531782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 532782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 5337b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (keyCode == KeyEvent.KEYCODE_DPAD_UP 5347b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert && mSuggestionsView.getSelectedItemPosition() == 0) { 5357b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert // Moved up from the top suggestion, restore the user query and focus query box 5367b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (DBG) Log.d(TAG, "Up and out"); 5377b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert restoreUserQuery(); 5387b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert return false; // let the framework handle the move 5397b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 5407b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert 5417b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT 5427b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) { 5437b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert // Moved left / right from a suggestion, keep current query, move 5447b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert // focus to query box, and move cursor to far left / right 5457b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (DBG) Log.d(TAG, "Left/right on a suggestion"); 5467b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert int cursorPos = (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) ? 0 : mQueryTextView.length(); 5477b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert mQueryTextView.setSelection(cursorPos); 5487b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert mQueryTextView.requestFocus(); 5497b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert // TODO: should we modify the list selection? 5507b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert return true; 5517b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 5527b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert 553782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return false; 554782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 555782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 5563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onSourceSelected() { 5573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "No suggestion selected"); 5583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert restoreUserQuery(); 5593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 561782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected int getSelectedPosition() { 562782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return mSuggestionsView.getSelectedPosition(); 563782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 564782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 5653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 5663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Hides the input method. 5673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 5683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void hideInputMethod() { 5693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); 5703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (imm != null) { 5713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert imm.hideSoftInputFromWindow(mQueryTextView.getWindowToken(), 0); 5723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5757b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert protected void showInputMethodForQuery() { 5767b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); 5777b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (imm != null) { 5786c8a8cb66ccf57347c7aed4260132d342b242b0fBjorn Bringert imm.showSoftInput(mQueryTextView, InputMethodManager.SHOW_IMPLICIT); 5797b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 5807b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 5817b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert 5823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 5833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Hides the input method when the suggestions get focus. 5843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 5853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class SuggestListFocusListener implements OnFocusChangeListener { 5863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onFocusChange(View v, boolean focused) { 5877b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (DBG) Log.d(TAG, "Suggestions focus change, now: " + focused); 5887b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (focused) { 5897b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert // The suggestions list got focus, hide the input method 5907b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert hideInputMethod(); 5917b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 5927b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 5937b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 5947b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert 5957b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert private class QueryTextViewFocusListener implements OnFocusChangeListener { 5967b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert public void onFocusChange(View v, boolean focused) { 5977b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (DBG) Log.d(TAG, "Query focus change, now: " + focused); 5987b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (focused) { 5997b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert // The query box got focus, show the input method if the 6007b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert // query box got focus? 6017b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert showInputMethodForQuery(); 6023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void startSearchProgress() { 607e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert // TODO: Do we need a progress indicator? 6083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void stopSearchProgress() { 611d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney Drawable animation = mSearchGoButton.getDrawable(); 612d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney if (animation instanceof Animatable) { 613d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney // TODO: Is this needed, or is it done automatically when the 614d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney // animation is removed? 615d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney ((Animatable) animation).stop(); 616d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney } 6173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSearchGoButton.setImageResource(R.drawable.ic_btn_search); 6183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void updateSuggestions(String query) { 6213d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney query = ltrim(query); 6223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert LatencyTracker latency = new LatencyTracker(TAG); 623ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert Suggestions suggestions = getSuggestionsProvider().getSuggestions(query); 6243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert latency.addEvent("getSuggestions_done"); 6253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (!suggestions.isDone()) { 6263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert suggestions.registerDataSetObserver(new ProgressUpdater(suggestions)); 6273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert startSearchProgress(); 628d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney } else { 629d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney stopSearchProgress(); 6303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 631185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsAdapter.setSuggestions(suggestions); 6323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert latency.addEvent("shortcuts_shown"); 6333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert long userVisibleLatency = latency.getUserVisibleLatency(); 6343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) { 6353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.d(TAG, "User visible latency (shortcuts): " + userVisibleLatency + " ms."); 6363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6397be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert private boolean forwardKeyToQueryTextView(int keyCode, KeyEvent event) { 6407be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert if (!event.isSystem() && !isDpadKey(keyCode)) { 6417be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert if (DBG) Log.d(TAG, "Forwarding key to query box: " + event); 6427be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert if (mQueryTextView.requestFocus()) { 6437be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return mQueryTextView.dispatchKeyEvent(event); 6447be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert } 6457be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert } 6467be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return false; 6477be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert } 6487be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert 6497be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert private boolean isDpadKey(int keyCode) { 6507be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert switch (keyCode) { 6517be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert case KeyEvent.KEYCODE_DPAD_UP: 6527be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert case KeyEvent.KEYCODE_DPAD_DOWN: 6537be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert case KeyEvent.KEYCODE_DPAD_LEFT: 6547be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert case KeyEvent.KEYCODE_DPAD_RIGHT: 6557be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert case KeyEvent.KEYCODE_DPAD_CENTER: 6567be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return true; 6577be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert default: 6587be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return false; 6597be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert } 6607be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert } 6617be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert 6623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 6633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Filters the suggestions list when the search text changes. 6643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 6653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class SearchTextWatcher implements TextWatcher { 6663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void afterTextChanged(Editable s) { 667e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert boolean empty = s.length() == 0; 668e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert if (empty != mQueryWasEmpty) { 669e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryWasEmpty = empty; 6705691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert updateUi(empty); 671e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 6723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mUpdateSuggestions) { 6733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String query = s == null ? "" : s.toString(); 6749ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setUserQuery(query); 6753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert updateSuggestions(query); 6763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void beforeTextChanged(CharSequence s, int start, int count, int after) { 6803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onTextChanged(CharSequence s, int start, int before, int count) { 6833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 6873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Handles non-text keys in the query text view. 6883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 6893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class QueryTextViewKeyListener implements View.OnKeyListener { 6903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean onKey(View view, int keyCode, KeyEvent event) { 6913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Handle IME search action key 6923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) { 693ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert onSearchClicked(Logger.SEARCH_METHOD_KEYBOARD); 6943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return false; 6963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 699782dd228e78e9294692d639597f96c26283968bbBjorn Bringert /** 700782dd228e78e9294692d639597f96c26283968bbBjorn Bringert * Handles key events on the search and voice search buttons, 701782dd228e78e9294692d639597f96c26283968bbBjorn Bringert * by refocusing to EditText. 702782dd228e78e9294692d639597f96c26283968bbBjorn Bringert */ 703782dd228e78e9294692d639597f96c26283968bbBjorn Bringert private class ButtonsKeyListener implements View.OnKeyListener { 704782dd228e78e9294692d639597f96c26283968bbBjorn Bringert public boolean onKey(View v, int keyCode, KeyEvent event) { 7057be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return forwardKeyToQueryTextView(keyCode, event); 706782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 707782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 708782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 709782dd228e78e9294692d639597f96c26283968bbBjorn Bringert /** 710782dd228e78e9294692d639597f96c26283968bbBjorn Bringert * Handles key events on the suggestions list view. 711782dd228e78e9294692d639597f96c26283968bbBjorn Bringert */ 712713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private class SuggestionsViewKeyListener implements View.OnKeyListener { 713782dd228e78e9294692d639597f96c26283968bbBjorn Bringert public boolean onKey(View v, int keyCode, KeyEvent event) { 714782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (event.getAction() == KeyEvent.ACTION_DOWN) { 715fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert int position = getSelectedPosition(); 716fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (onSuggestionKeyDown(position, keyCode, event)) { 7177be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return true; 718782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 719782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 7207be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return forwardKeyToQueryTextView(keyCode, event); 721782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 722782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 723782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 724185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert private class InputMethodCloser implements SuggestionsView.InteractionListener { 725185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert public void onInteraction() { 726185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert hideInputMethod(); 727185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert } 728185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert } 729185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 730185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert private class ClickHandler implements SuggestionClickListener { 731fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public void onSuggestionClicked(int position) { 732fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert launchSuggestion(position); 7333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 735fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public boolean onSuggestionLongClicked(int position) { 736fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return SearchActivity.this.onSuggestionLongClicked(position); 737713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 7383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7407b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert private class SelectionHandler implements SuggestionSelectionListener { 741fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public void onSuggestionSelected(int position) { 742fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert SuggestionCursor suggestions = getSuggestions(); 743fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert suggestions.moveTo(position); 744fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert String displayQuery = suggestions.getSuggestionDisplayQuery(); 745fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (TextUtils.isEmpty(displayQuery)) { 746fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert restoreUserQuery(); 747fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } else { 748fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert setQuery(displayQuery, false); 749fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 750fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 751fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 752fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public void onNothingSelected() { 753fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // This happens when a suggestion has been selected with the 754fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // dpad / trackball and then a different UI element is touched. 755fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // Do nothing, since we want to keep the query of the selection 756fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // in the search box. 7577b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 7587b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 7597b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert 7603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 7612617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert * Listens for clicks on the source selector. 7623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 7633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class SearchGoButtonClickListener implements View.OnClickListener { 7643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onClick(View view) { 765ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert onSearchClicked(Logger.SEARCH_METHOD_BUTTON); 7663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 7702617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert * Listens for clicks on the search button. 7712617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert */ 772fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private class CorpusIndicatorClickListener implements View.OnClickListener { 7732617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert public void onClick(View view) { 77441fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert showCorpusSelectionDialog(); 7752617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 7762617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 7772617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 7782617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert /** 7793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Listens for clicks on the voice search button. 7803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 7813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class VoiceSearchButtonClickListener implements View.OnClickListener { 7823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onClick(View view) { 7833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert onVoiceSearchClicked(); 7843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 7883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Updates the progress bar when the suggestions adapter changes its progress. 7893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 7903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class ProgressUpdater extends DataSetObserver { 7913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final Suggestions mSuggestions; 7923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public ProgressUpdater(Suggestions suggestions) { 7943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSuggestions = suggestions; 7953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 7983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onChanged() { 7993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mSuggestions.isDone()) { 8003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert stopSearchProgress(); 8013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 8023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 8033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 804713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 8053d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney private static String ltrim(String text) { 8063d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney int start = 0; 8073d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney int length = text.length(); 8083d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney while (start < length && Character.isWhitespace(text.charAt(start))) { 8093d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney start++; 8103d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney } 8113d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney return start > 0 ? text.substring(start, length) : text; 8123d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney } 8133d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney 8143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert} 815