SearchActivity.java revision 754cb6b769c5955fc707a6c5ab6689b64df102b3
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; 22185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionsAdapter; 23185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionsView; 24185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.app.Activity; 263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.app.SearchManager; 27dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringertimport android.content.DialogInterface; 283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.Intent; 2921bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringertimport android.database.DataSetObserver; 30d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinneyimport android.graphics.drawable.Drawable; 31fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.net.Uri; 323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.os.Bundle; 3311234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringertimport android.os.Debug; 344ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringertimport android.os.Handler; 353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.Editable; 363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.TextUtils; 373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.TextWatcher; 383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.util.Log; 393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.KeyEvent; 403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.Menu; 413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.View; 423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.View.OnFocusChangeListener; 433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.inputmethod.InputMethodManager; 44145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringertimport android.widget.AbsListView; 453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.widget.EditText; 463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.widget.ImageButton; 473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4811234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringertimport java.io.File; 49e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringertimport java.util.Collection; 50ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert 513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/** 523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * The main activity for Quick Search Box. Shows the search UI. 533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpublic class SearchActivity extends Activity { 563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 57754cb6b769c5955fc707a6c5ab6689b64df102b3Mathew Inwood private static final boolean DBG = false; 580484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private static final String TAG = "QSB.SearchActivity"; 5911234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert private static final boolean TRACE = false; 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"; 73839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert private static final String INSTANCE_KEY_QUERY = "query"; 74713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 75f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert // Measures time from for last onCreate()/onNewIntent() call. 76f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert private LatencyTracker mStartLatencyTracker; 77ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert // Whether QSB is starting. True between the calls to onCreate()/onNewIntent() and onResume(). 78ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert private boolean mStarting; 79ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert // True if the user has taken some action, e.g. launching a search, voice search, 80ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert // or suggestions, since QSB was last started. 81ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert private boolean mTookAction; 82ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert 83f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert private CorpusSelectionDialog mCorpusSelectionDialog; 84f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert 85185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert protected SuggestionsAdapter mSuggestionsAdapter; 86185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 8721bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert private CorporaObserver mCorporaObserver; 8821bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert 893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected EditText mQueryTextView; 90e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert // True if the query was empty on the previous call to updateQuery() 91e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert protected boolean mQueryWasEmpty = true; 923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected SuggestionsView mSuggestionsView; 943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected ImageButton mSearchGoButton; 963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected ImageButton mVoiceSearchButton; 97a576b1abd602c08dcf0d470facc43fac0243b07cBjorn Bringert protected ImageButton mCorpusIndicator; 983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 9981a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert private VoiceSearch mVoiceSearch; 1003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 101fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private Corpus mCorpus; 1022617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert private Bundle mAppSearchData; 103713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private boolean mUpdateSuggestions; 1043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 105d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood private final Handler mHandler = new Handler(); 106d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood private final Runnable mUpdateSuggestionsTask = new Runnable() { 1074ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert public void run() { 1084ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert updateSuggestions(getQuery()); 1094ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert } 1104ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert }; 1114ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert 112d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood private final Runnable mShowInputMethodTask = new Runnable() { 113d98911178013162737fbba74387b51d2a08b0493Amith Yamasani public void run() { 114d98911178013162737fbba74387b51d2a08b0493Amith Yamasani showInputMethodForQuery(); 115d98911178013162737fbba74387b51d2a08b0493Amith Yamasani } 116d98911178013162737fbba74387b51d2a08b0493Amith Yamasani }; 117d98911178013162737fbba74387b51d2a08b0493Amith Yamasani 1183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** Called when the activity is first created. */ 1193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 1203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onCreate(Bundle savedInstanceState) { 12111234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert if (TRACE) startMethodTracing(); 122ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert recordStartTime(); 1233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "onCreate()"); 1243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onCreate(savedInstanceState); 125713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 1266ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert setContentView(); 127816804b67619af133860a1e28e92f58bc642260dBjorn Bringert mSuggestionsAdapter = getQsbApplication().createSuggestionsAdapter(); 128185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 1293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQueryTextView = (EditText) findViewById(R.id.search_src_text); 1303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSuggestionsView = (SuggestionsView) findViewById(R.id.suggestions); 131782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mSuggestionsView.setSuggestionClickListener(new ClickHandler()); 132145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert mSuggestionsView.setOnScrollListener(new InputMethodCloser()); 133713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSuggestionsView.setOnKeyListener(new SuggestionsViewKeyListener()); 1347b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert mSuggestionsView.setOnFocusChangeListener(new SuggestListFocusListener()); 1353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSearchGoButton = (ImageButton) findViewById(R.id.search_go_btn); 1373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mVoiceSearchButton = (ImageButton) findViewById(R.id.search_voice_btn); 138a576b1abd602c08dcf0d470facc43fac0243b07cBjorn Bringert mCorpusIndicator = (ImageButton) findViewById(R.id.corpus_indicator); 1393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 14081a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert mVoiceSearch = new VoiceSearch(this); 1413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 142782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mQueryTextView.addTextChangedListener(new SearchTextWatcher()); 143782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mQueryTextView.setOnKeyListener(new QueryTextViewKeyListener()); 1447b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert mQueryTextView.setOnFocusChangeListener(new QueryTextViewFocusListener()); 145782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 146fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert mCorpusIndicator.setOnClickListener(new CorpusIndicatorClickListener()); 1472617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 148782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mSearchGoButton.setOnClickListener(new SearchGoButtonClickListener()); 149782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 150782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mVoiceSearchButton.setOnClickListener(new VoiceSearchButtonClickListener()); 1517be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert 1527be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert ButtonsKeyListener buttonsKeyListener = new ButtonsKeyListener(); 1537be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert mSearchGoButton.setOnKeyListener(buttonsKeyListener); 1547be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert mVoiceSearchButton.setOnKeyListener(buttonsKeyListener); 155fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert mCorpusIndicator.setOnKeyListener(buttonsKeyListener); 156713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 1579ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mUpdateSuggestions = true; 1589ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert 1599ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // First get setup from intent 1609ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert Intent intent = getIntent(); 1619ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setupFromIntent(intent); 1629ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // Then restore any saved instance state 1639ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert restoreInstanceState(savedInstanceState); 1649ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert 165713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert // Do this at the end, to avoid updating the list view when setSource() 166713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert // is called. 167713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSuggestionsView.setAdapter(mSuggestionsAdapter); 16821bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert 16921bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert mCorporaObserver = new CorporaObserver(); 17021bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert getCorpora().registerDataSetObserver(mCorporaObserver); 1719ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert } 172713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 1736ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert protected void setContentView() { 1746ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert setContentView(R.layout.search_activity); 1756ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert } 1766ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert 17711234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert private void startMethodTracing() { 17811234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert File traceDir = getDir("traces", 0); 17911234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert String traceFile = new File(traceDir, "qsb.trace").getAbsolutePath(); 18011234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert Debug.startMethodTracing(traceFile); 18111234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert } 18211234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert 1839ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert @Override 1849ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert protected void onNewIntent(Intent intent) { 185839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert if (DBG) Log.d(TAG, "onNewIntent()"); 186ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert recordStartTime(); 1879ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setIntent(intent); 1889ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setupFromIntent(intent); 1899ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert } 1909ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert 191ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert private void recordStartTime() { 192f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert mStartLatencyTracker = new LatencyTracker(); 193ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert mStarting = true; 194ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert mTookAction = false; 195ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert } 196ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert 1979ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert protected void restoreInstanceState(Bundle savedInstanceState) { 1989ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert if (savedInstanceState == null) return; 199fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert String corpusName = savedInstanceState.getString(INSTANCE_KEY_CORPUS); 200839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert String query = savedInstanceState.getString(INSTANCE_KEY_QUERY); 20121bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert setCorpus(corpusName); 202839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert setQuery(query, false); 203713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 204713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 205713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert @Override 2069ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert protected void onSaveInstanceState(Bundle outState) { 2079ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert super.onSaveInstanceState(outState); 2089ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // We don't save appSearchData, since we always get the value 2099ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // from the intent and the user can't change it. 210fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 21121bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert outState.putString(INSTANCE_KEY_CORPUS, getCorpusName()); 212839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert outState.putString(INSTANCE_KEY_QUERY, getQuery()); 213713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 214713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 215713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private void setupFromIntent(Intent intent) { 216713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert if (DBG) Log.d(TAG, "setupFromIntent(" + intent.toUri(0) + ")"); 21721bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert String corpusName = getCorpusNameFromUri(intent.getData()); 2182617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert String query = intent.getStringExtra(SearchManager.QUERY); 2192617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert Bundle appSearchData = intent.getBundleExtra(SearchManager.APP_DATA); 220839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert boolean selectAll = intent.getBooleanExtra(SearchManager.EXTRA_SELECT_QUERY, false); 2212617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 22221bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert setCorpus(corpusName); 223839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert setQuery(query, selectAll); 224c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert mAppSearchData = appSearchData; 2252617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 22611c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert if (startedIntoCorpusSelectionDialog()) { 22741fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert showCorpusSelectionDialog(); 2282617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 2299ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert } 2309ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert 23111c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert public boolean startedIntoCorpusSelectionDialog() { 23211c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert return INTENT_ACTION_QSB_AND_SELECT_CORPUS.equals(getIntent().getAction()); 23311c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert } 23411c44a74cb2519c0c8630486784aa916b964070eBjorn Bringert 235dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert /** 236dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert * Removes corpus selector intent action, so that BACK works normally after 237dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert * dismissing and reopening the corpus selector. 238dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert */ 239dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert private void clearStartedIntoCorpusSelectionDialog() { 240dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert Intent oldIntent = getIntent(); 241dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert if (SearchActivity.INTENT_ACTION_QSB_AND_SELECT_CORPUS.equals(oldIntent.getAction())) { 242dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert Intent newIntent = new Intent(oldIntent); 243dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert newIntent.setAction(SearchManager.INTENT_ACTION_GLOBAL_SEARCH); 244dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert setIntent(newIntent); 245dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert } 246dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert } 247dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert 248fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public static Uri getCorpusUri(Corpus corpus) { 249fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (corpus == null) return null; 250fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return new Uri.Builder() 251fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert .scheme(SCHEME_CORPUS) 252fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert .authority(corpus.getName()) 253fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert .build(); 254fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 255fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 25621bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert private String getCorpusNameFromUri(Uri uri) { 257fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (uri == null) return null; 258fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (!SCHEME_CORPUS.equals(uri.getScheme())) return null; 25921bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert return uri.getAuthority(); 260fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 261fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 262fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private Corpus getCorpus(String sourceName) { 2630ccab5903ba2c64ec4cdd33dbcea91b1e279d556Bjorn Bringert if (sourceName == null) return null; 264fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert Corpus corpus = getCorpora().getCorpus(sourceName); 265fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (corpus == null) { 266fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert Log.w(TAG, "Unknown corpus " + sourceName); 2679ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert return null; 268713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 269fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return corpus; 270713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 271713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 27221bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert private void setCorpus(String corpusName) { 27321bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert if (DBG) Log.d(TAG, "setCorpus(" + corpusName + ")"); 27421bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert mCorpus = getCorpus(corpusName); 2759ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert Drawable sourceIcon; 27621bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert if (mCorpus == null) { 277c5a3ecb62318a6be1d1a626a36b52829e989f740Bjorn Bringert sourceIcon = getCorpusViewFactory().getGlobalSearchIcon(); 278713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } else { 27921bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert sourceIcon = mCorpus.getCorpusIcon(); 280713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 28121bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert mSuggestionsAdapter.setCorpus(mCorpus); 282a576b1abd602c08dcf0d470facc43fac0243b07cBjorn Bringert mCorpusIndicator.setImageDrawable(sourceIcon); 2833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2845691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert updateUi(getQuery().length() == 0); 2850484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 2860484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 28721bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert private String getCorpusName() { 28821bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert return mCorpus == null ? null : mCorpus.getName(); 28921bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert } 29021bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert 2913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private QsbApplication getQsbApplication() { 2923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return (QsbApplication) getApplication(); 2933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2954ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert private Config getConfig() { 2964ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert return getQsbApplication().getConfig(); 2974ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert } 2984ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert 299fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private Corpora getCorpora() { 300fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return getQsbApplication().getCorpora(); 301fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 302fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 3033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private ShortcutRepository getShortcutRepository() { 3043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getQsbApplication().getShortcutRepository(); 3053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 307ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert private SuggestionsProvider getSuggestionsProvider() { 30847d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert return getQsbApplication().getSuggestionsProvider(); 30947d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert } 31047d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert 311c5a3ecb62318a6be1d1a626a36b52829e989f740Bjorn Bringert private CorpusViewFactory getCorpusViewFactory() { 312c5a3ecb62318a6be1d1a626a36b52829e989f740Bjorn Bringert return getQsbApplication().getCorpusViewFactory(); 313185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert } 314185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 315ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert private Logger getLogger() { 316ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert return getQsbApplication().getLogger(); 317ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert } 318ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert 3193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 3203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onDestroy() { 3213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "onDestroy()"); 3223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onDestroy(); 32321bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert getCorpora().unregisterDataSetObserver(mCorporaObserver); 324185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsView.setAdapter(null); // closes mSuggestionsAdapter 3253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 3283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onStop() { 3299ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert if (DBG) Log.d(TAG, "onStop()"); 330f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert if (!mTookAction) { 331f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert // TODO: This gets logged when starting other activities, e.g. by opening he search 332f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert // settings, or clicking a notification in the status bar. 333f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert getLogger().logExit(getCurrentSuggestions(), getQuery().length()); 334f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert } 3359ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // Close all open suggestion cursors. The query will be redone in onResume() 3363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // if we come back to this activity. 337185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsAdapter.setSuggestions(null); 33894e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney getQsbApplication().getShortcutRefresher().reset(); 339f69873ae02e6d8f8a550f5fa43b5b1f2cbea96ffBjorn Bringert dismissCorpusSelectionDialog(); 3403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onStop(); 3413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 344839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert protected void onRestart() { 345839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert if (DBG) Log.d(TAG, "onRestart()"); 346839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert super.onRestart(); 347839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert } 348839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert 349839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert @Override 350b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert protected void onResume() { 3519ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert if (DBG) Log.d(TAG, "onResume()"); 352b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert super.onResume(); 35311234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert updateSuggestionsBuffered(); 354dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert if (!isCorpusSelectionDialogShowing()) { 355dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert mQueryTextView.requestFocus(); 356dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert } 35711234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert if (TRACE) Debug.stopMethodTracing(); 358b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert } 359b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert 360b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert @Override 3613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean onCreateOptionsMenu(Menu menu) { 3623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onCreateOptionsMenu(menu); 36326d85260316193a1aeff5d407d4f32f5297be012Bjorn Bringert SearchSettings.addSearchSettingsMenuItem(this, menu); 3643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return true; 3653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 367d98911178013162737fbba74387b51d2a08b0493Amith Yamasani @Override 368d98911178013162737fbba74387b51d2a08b0493Amith Yamasani public void onWindowFocusChanged(boolean hasFocus) { 369d98911178013162737fbba74387b51d2a08b0493Amith Yamasani super.onWindowFocusChanged(hasFocus); 370d98911178013162737fbba74387b51d2a08b0493Amith Yamasani if (hasFocus) { 371d98911178013162737fbba74387b51d2a08b0493Amith Yamasani // Launch the IME after a bit 372d98911178013162737fbba74387b51d2a08b0493Amith Yamasani mHandler.postDelayed(mShowInputMethodTask, 0); 373d98911178013162737fbba74387b51d2a08b0493Amith Yamasani } 374d98911178013162737fbba74387b51d2a08b0493Amith Yamasani } 375d98911178013162737fbba74387b51d2a08b0493Amith Yamasani 376713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert protected String getQuery() { 3773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert CharSequence q = mQueryTextView.getText(); 3783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return q == null ? "" : q.toString(); 3793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Sets the text in the query box. Does not update the suggestions, 3833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * and does not change the saved user-entered query. 3843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * {@link #restoreUserQuery()} will restore the query to the last 3853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * user-entered query. 3863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 3873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void setQuery(String query, boolean selectAll) { 3883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mUpdateSuggestions = false; 3893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQueryTextView.setText(query); 3903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert setTextSelection(selectAll); 3913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mUpdateSuggestions = true; 3923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Sets the text selection in the query text view. 3963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 3973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * @param selectAll If {@code true}, selects the entire query. 3983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * If {@false}, no characters are selected, and the cursor is placed 3993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * at the end of the query. 4003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 4013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void setTextSelection(boolean selectAll) { 4023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (selectAll) { 4035691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert mQueryTextView.selectAll(); 4043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else { 4053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQueryTextView.setSelection(mQueryTextView.length()); 4063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 40918959800eddb7127e4fd9b24e91458d0584cc257Mathew Inwood protected void updateUi(boolean queryEmpty) { 4105691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert updateQueryTextView(queryEmpty); 4115691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert updateSearchGoButton(queryEmpty); 4125691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert updateVoiceSearchButton(queryEmpty); 4135691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert } 4145691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert 415e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert private void updateQueryTextView(boolean queryEmpty) { 416e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert if (queryEmpty) { 4175691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert if (mCorpus == null || mCorpus.isWebCorpus()) { 4185691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert mQueryTextView.setBackgroundResource(R.drawable.textfield_search_empty_google); 4195691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert mQueryTextView.setHint(null); 4205691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert } else { 4215691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert mQueryTextView.setBackgroundResource(R.drawable.textfield_search_empty); 4225691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert mQueryTextView.setHint(mCorpus.getHint()); 4235691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert } 424e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } else { 425e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryTextView.setBackgroundResource(R.drawable.textfield_search); 426e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 427e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 428e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert 429e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert private void updateSearchGoButton(boolean queryEmpty) { 430e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert if (queryEmpty) { 431e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mSearchGoButton.setVisibility(View.GONE); 432e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } else { 433e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mSearchGoButton.setVisibility(View.VISIBLE); 434e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 435e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 436e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert 437e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert protected void updateVoiceSearchButton(boolean queryEmpty) { 43881a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert if (queryEmpty && mVoiceSearch.shouldShowVoiceSearch(mCorpus)) { 439e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mVoiceSearchButton.setVisibility(View.VISIBLE); 440e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryTextView.setPrivateImeOptions(IME_OPTION_NO_MICROPHONE); 441e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } else { 442e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mVoiceSearchButton.setVisibility(View.GONE); 443e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryTextView.setPrivateImeOptions(null); 444e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 445e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 446e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert 44741fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert protected void showCorpusSelectionDialog() { 448f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert if (mCorpusSelectionDialog == null) { 449f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert mCorpusSelectionDialog = new CorpusSelectionDialog(this); 450f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert mCorpusSelectionDialog.setOwnerActivity(this); 451dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert mCorpusSelectionDialog.setOnDismissListener(new CorpusSelectorDismissListener()); 452f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert mCorpusSelectionDialog.setOnCorpusSelectedListener(new CorpusSelectionListener()); 4532617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 454f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert mCorpusSelectionDialog.show(mCorpus); 4552617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4562617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 457dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert protected boolean isCorpusSelectionDialogShowing() { 458dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert return mCorpusSelectionDialog != null && mCorpusSelectionDialog.isShowing(); 459dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert } 460dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert 461f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert protected void dismissCorpusSelectionDialog() { 462f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert if (mCorpusSelectionDialog != null) { 463f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert mCorpusSelectionDialog.dismiss(); 4642617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4652617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 4662617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 467dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood /** 468dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood * @return true if a search was performed as a result of this click, false otherwise. 469dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood */ 470dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood protected boolean onSearchClicked(int method) { 471267d93c257837859e7a31f41f9276c086d1dd82bBjorn Bringert String query = ltrim(getQuery()); 4723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Search clicked, query=" + query); 473eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert 474eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert // Don't do empty queries 475dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood if (TextUtils.getTrimmedLength(query) == 0) return false; 476eba26da75665ac3b9a411e74267395f332ff851aBjorn Bringert 47781a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert Corpus searchCorpus = getSearchCorpus(); 478dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood if (searchCorpus == null) return false; 479c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 480ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert mTookAction = true; 481c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 482c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Log search start 483fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert getLogger().logSearch(mCorpus, method, query.length()); 484c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 485c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Create shortcut 486c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert SuggestionData searchShortcut = searchCorpus.createSearchShortcut(query); 487c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert if (searchShortcut != null) { 488c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert DataSuggestionCursor cursor = new DataSuggestionCursor(query); 489c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert cursor.add(searchShortcut); 490c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert getShortcutRepository().reportClick(cursor, 0); 491c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert } 492c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 493c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Start search 494c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert Intent intent = searchCorpus.createSearchIntent(query, mAppSearchData); 49581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert launchIntent(intent); 496dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood return true; 4973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onVoiceSearchClicked() { 5003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Voice Search clicked"); 50181a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert Corpus searchCorpus = getSearchCorpus(); 502c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert if (searchCorpus == null) return; 503c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 504535931433926d342c6277034cad91143ae28b72dBjorn Bringert mTookAction = true; 505535931433926d342c6277034cad91143ae28b72dBjorn Bringert 506c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Log voice search start 507c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert getLogger().logVoiceSearch(searchCorpus); 508ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert 509c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Start voice search 510c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert Intent intent = searchCorpus.createVoiceSearchIntent(mAppSearchData); 51181a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert launchIntent(intent); 51281a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert } 51381a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert 51481a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert /** 51581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert * Gets the corpus to use for any searches. This is the web corpus in "All" mode, 51681a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert * and the selected corpus otherwise. 51781a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert */ 518ca9c7b7bc0183aa1b6d160bf76597c96e70831f6Mathew Inwood protected Corpus getSearchCorpus() { 51981a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert if (mCorpus != null) { 52081a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert return mCorpus; 52181a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert } else { 52281a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert Corpus webCorpus = getCorpora().getWebCorpus(); 52381a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert if (webCorpus == null) { 52481a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert Log.e(TAG, "No web corpus"); 52581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert } 52681a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert return webCorpus; 52781a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert } 528c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert } 529c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 530e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringert protected SuggestionCursor getCurrentSuggestions() { 531fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return mSuggestionsAdapter.getCurrentSuggestions(); 532782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 533782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 53481a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert protected void launchIntent(Intent intent) { 53581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert if (intent == null) { 53681a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert return; 53781a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert } 53881a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert try { 53981a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert startActivity(intent); 54081a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert } catch (RuntimeException ex) { 54181a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert // Since the intents for suggestions specified by suggestion providers, 54281a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert // guard against them not being handled, not allowed, etc. 54381a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert Log.e(TAG, "Failed to start " + intent.toUri(0), ex); 54481a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert } 54581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert } 54681a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert 547fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected boolean launchSuggestion(int position) { 5486f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert SuggestionCursor suggestions = getCurrentSuggestions(); 5496f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert if (position < 0 || position >= suggestions.getCount()) { 5506f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert Log.w(TAG, "Tried to launch invalid suggestion " + position); 5516f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert return false; 5526f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert } 5536f8fc42e68237bfb6f474faff8086d910d2934d5Bjorn Bringert 554fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (DBG) Log.d(TAG, "Launching suggestion " + position); 555ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert mTookAction = true; 556e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringert 557c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Log suggestion click 558e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringert Collection<Corpus> corpora = mSuggestionsAdapter.getSuggestions().getIncludedCorpora(); 559fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert getLogger().logSuggestionClick(position, suggestions, corpora); 560ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert 561c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Create shortcut 562fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert getShortcutRepository().reportClick(suggestions, position); 563c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 564c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert // Launch intent 56581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert suggestions.moveTo(position); 56681a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert Intent intent = suggestions.getSuggestionIntent(mAppSearchData); 56781a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert launchIntent(intent); 568c29c9f854db8fa0c85f17cc32bae33dc17c6b127Bjorn Bringert 5693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return true; 5703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 572fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected boolean onSuggestionLongClicked(int position) { 573fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (DBG) Log.d(TAG, "Long clicked on suggestion " + position); 5743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return false; 5753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 577fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected boolean onSuggestionKeyDown(int position, int keyCode, KeyEvent event) { 578782dd228e78e9294692d639597f96c26283968bbBjorn Bringert // Treat enter or search as a click 579782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH) { 580fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return launchSuggestion(position); 581782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 582782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 583782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return false; 584782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 585782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 586782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected int getSelectedPosition() { 587782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return mSuggestionsView.getSelectedPosition(); 588782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 589782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 5903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 5913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Hides the input method. 5923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 5933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void hideInputMethod() { 5943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); 5953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (imm != null) { 5963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert imm.hideSoftInputFromWindow(mQueryTextView.getWindowToken(), 0); 5973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6007b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert protected void showInputMethodForQuery() { 6017b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); 6027b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (imm != null) { 603d98911178013162737fbba74387b51d2a08b0493Amith Yamasani imm.showSoftInput(mQueryTextView, 0); 6047b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 6057b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 6067b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert 607f5e1499b48ac06de4e6e6460a7f14c3a7ac4eaddMathew Inwood protected void onSuggestionListFocusChange(boolean focused) { 608f5e1499b48ac06de4e6e6460a7f14c3a7ac4eaddMathew Inwood } 609f5e1499b48ac06de4e6e6460a7f14c3a7ac4eaddMathew Inwood 610f5e1499b48ac06de4e6e6460a7f14c3a7ac4eaddMathew Inwood protected void onQueryTextViewFocusChange(boolean focused) { 611f5e1499b48ac06de4e6e6460a7f14c3a7ac4eaddMathew Inwood } 612f5e1499b48ac06de4e6e6460a7f14c3a7ac4eaddMathew Inwood 6133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 6143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Hides the input method when the suggestions get focus. 6153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 6163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class SuggestListFocusListener implements OnFocusChangeListener { 6173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onFocusChange(View v, boolean focused) { 6187b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (DBG) Log.d(TAG, "Suggestions focus change, now: " + focused); 6197b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (focused) { 6207b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert // The suggestions list got focus, hide the input method 6217b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert hideInputMethod(); 6227b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 623f5e1499b48ac06de4e6e6460a7f14c3a7ac4eaddMathew Inwood onSuggestionListFocusChange(focused); 6247b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 6257b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert } 6267b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert 6277b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert private class QueryTextViewFocusListener implements OnFocusChangeListener { 6287b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert public void onFocusChange(View v, boolean focused) { 6297b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (DBG) Log.d(TAG, "Query focus change, now: " + focused); 6307b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert if (focused) { 631dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert // The query box got focus, show the input method 6327b9d59cd76eecd7645072c6728e2faf9ff9e180aBjorn Bringert showInputMethodForQuery(); 6333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 634f5e1499b48ac06de4e6e6460a7f14c3a7ac4eaddMathew Inwood onQueryTextViewFocusChange(focused); 6353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 638e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney private int getMaxSuggestions() { 639e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney Config config = getConfig(); 640e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney return mCorpus == null 641e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney ? config.getMaxPromotedSuggestions() 642e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney : config.getMaxResultsPerSource(); 643e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney } 644e6f46632869a288c82b75187af166931f82a6e12Bryan Mawhinney 6454ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert private void updateSuggestionsBuffered() { 646d98911178013162737fbba74387b51d2a08b0493Amith Yamasani mHandler.removeCallbacks(mUpdateSuggestionsTask); 6474ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert long delay = getConfig().getTypingUpdateSuggestionsDelayMillis(); 648d98911178013162737fbba74387b51d2a08b0493Amith Yamasani mHandler.postDelayed(mUpdateSuggestionsTask, delay); 6494ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert } 6504ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert 6516ae65b29ce9313a4f0624ef825f75151db5ec2feBjorn Bringert protected void updateSuggestions(String query) { 6523cb8178193a41f6c74ee396c318385a50dd624e1Mathew Inwood 6533cb8178193a41f6c74ee396c318385a50dd624e1Mathew Inwood query = ltrim(query); 6543cb8178193a41f6c74ee396c318385a50dd624e1Mathew Inwood Suggestions suggestions = getSuggestionsProvider().getSuggestions( 6553cb8178193a41f6c74ee396c318385a50dd624e1Mathew Inwood query, mCorpus, getMaxSuggestions()); 6563cb8178193a41f6c74ee396c318385a50dd624e1Mathew Inwood 65711234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert // Log start latency if this is the first suggestions update 65811234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert if (mStarting) { 65911234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert mStarting = false; 66011234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert String source = getIntent().getStringExtra(Search.SOURCE); 66111234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert int latency = mStartLatencyTracker.getLatency(); 6623cb8178193a41f6c74ee396c318385a50dd624e1Mathew Inwood getLogger().logStart(latency, source, mCorpus, suggestions.getExpectedCorpora()); 66311234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert } 66411234b9966c6b0e5c17d00e3b973c0d49a8d1f57Bjorn Bringert 665185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsAdapter.setSuggestions(suggestions); 6663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6687be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert private boolean forwardKeyToQueryTextView(int keyCode, KeyEvent event) { 6697be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert if (!event.isSystem() && !isDpadKey(keyCode)) { 6707be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert if (DBG) Log.d(TAG, "Forwarding key to query box: " + event); 6717be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert if (mQueryTextView.requestFocus()) { 6727be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return mQueryTextView.dispatchKeyEvent(event); 6737be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert } 6747be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert } 6757be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return false; 6767be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert } 6777be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert 6787be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert private boolean isDpadKey(int keyCode) { 6797be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert switch (keyCode) { 6807be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert case KeyEvent.KEYCODE_DPAD_UP: 6817be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert case KeyEvent.KEYCODE_DPAD_DOWN: 6827be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert case KeyEvent.KEYCODE_DPAD_LEFT: 6837be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert case KeyEvent.KEYCODE_DPAD_RIGHT: 6847be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert case KeyEvent.KEYCODE_DPAD_CENTER: 6857be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return true; 6867be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert default: 6877be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return false; 6887be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert } 6897be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert } 6907be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert 6913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 6923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Filters the suggestions list when the search text changes. 6933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 6943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class SearchTextWatcher implements TextWatcher { 6953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void afterTextChanged(Editable s) { 696e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert boolean empty = s.length() == 0; 697e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert if (empty != mQueryWasEmpty) { 698e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert mQueryWasEmpty = empty; 6995691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert updateUi(empty); 700e4f5c630a1c9cdf75fe751dc728729c3ecb7ae07Bjorn Bringert } 7013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mUpdateSuggestions) { 7024ef1338a23b040df2ef180c48ff85e14a9d70906Bjorn Bringert updateSuggestionsBuffered(); 7033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void beforeTextChanged(CharSequence s, int start, int count, int after) { 7073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onTextChanged(CharSequence s, int start, int before, int count) { 7103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 7143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Handles non-text keys in the query text view. 7153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 7163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class QueryTextViewKeyListener implements View.OnKeyListener { 7173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean onKey(View view, int keyCode, KeyEvent event) { 7183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Handle IME search action key 7193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) { 720d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood // if no action was taken, consume the key event so that the keyboard 721d6b9bd42f22582a8ccec657bd6d715465de98ec9Mathew Inwood // remains on screen. 722dd6d9a1a8d559c87f54412eb4e6569ed62193d60Mathew Inwood return !onSearchClicked(Logger.SEARCH_METHOD_KEYBOARD); 7233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return false; 7253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 728782dd228e78e9294692d639597f96c26283968bbBjorn Bringert /** 729782dd228e78e9294692d639597f96c26283968bbBjorn Bringert * Handles key events on the search and voice search buttons, 730782dd228e78e9294692d639597f96c26283968bbBjorn Bringert * by refocusing to EditText. 731782dd228e78e9294692d639597f96c26283968bbBjorn Bringert */ 732782dd228e78e9294692d639597f96c26283968bbBjorn Bringert private class ButtonsKeyListener implements View.OnKeyListener { 733782dd228e78e9294692d639597f96c26283968bbBjorn Bringert public boolean onKey(View v, int keyCode, KeyEvent event) { 7347be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return forwardKeyToQueryTextView(keyCode, event); 735782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 736782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 737782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 738782dd228e78e9294692d639597f96c26283968bbBjorn Bringert /** 739782dd228e78e9294692d639597f96c26283968bbBjorn Bringert * Handles key events on the suggestions list view. 740782dd228e78e9294692d639597f96c26283968bbBjorn Bringert */ 741713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private class SuggestionsViewKeyListener implements View.OnKeyListener { 742782dd228e78e9294692d639597f96c26283968bbBjorn Bringert public boolean onKey(View v, int keyCode, KeyEvent event) { 743782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (event.getAction() == KeyEvent.ACTION_DOWN) { 744fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert int position = getSelectedPosition(); 745fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (onSuggestionKeyDown(position, keyCode, event)) { 746839a9fd2828f37c9dc8345f93aefa5b8ad2f857fBjorn Bringert return true; 747782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 748782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 7497be9c66fdc2e4df2e998d79a11bcf737ffddc2dcBjorn Bringert return forwardKeyToQueryTextView(keyCode, event); 750782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 751782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 752782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 753145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert private class InputMethodCloser implements SuggestionsView.OnScrollListener { 754145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert 755145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, 756145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert int totalItemCount) { 757145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert } 758145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert 759145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert public void onScrollStateChanged(AbsListView view, int scrollState) { 760185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert hideInputMethod(); 761185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert } 762185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert } 763185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 764185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert private class ClickHandler implements SuggestionClickListener { 765fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public void onSuggestionClicked(int position) { 766fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert launchSuggestion(position); 7673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 769fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public boolean onSuggestionLongClicked(int position) { 770fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return SearchActivity.this.onSuggestionLongClicked(position); 771713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 772145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert 773145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert public void onSuggestionQueryRefineClicked(int position) { 774145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert if (DBG) Log.d(TAG, "query refine clicked, pos " + position); 775145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert SuggestionCursor suggestions = getCurrentSuggestions(); 776145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert if (suggestions != null) { 777145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert suggestions.moveTo(position); 778145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert String query = suggestions.getSuggestionQuery(); 779145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert if (!TextUtils.isEmpty(query)) { 780145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert query += " "; 781145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert setQuery(query, false); 782145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert updateSuggestions(query); 783145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert } 784145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert } 785145693e12b77c193a65b7eaa038a272dd1f48f33Bjorn Bringert } 7863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 7892617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert * Listens for clicks on the source selector. 7903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 7913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class SearchGoButtonClickListener implements View.OnClickListener { 7923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onClick(View view) { 793ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert onSearchClicked(Logger.SEARCH_METHOD_BUTTON); 7943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 7963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 7982617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert * Listens for clicks on the search button. 7992617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert */ 800fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private class CorpusIndicatorClickListener implements View.OnClickListener { 8012617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert public void onClick(View view) { 80241fe9d1fc461c42907250d44d3537909e4c46a7dBjorn Bringert showCorpusSelectionDialog(); 8032617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 804f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert } 805f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert 806dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert private class CorpusSelectorDismissListener implements DialogInterface.OnDismissListener { 807dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert public void onDismiss(DialogInterface dialog) { 808dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert if (DBG) Log.d(TAG, "Corpus selector dismissed"); 809dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert clearStartedIntoCorpusSelectionDialog(); 810dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert } 811dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert } 812dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert 813f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert private class CorpusSelectionListener 814f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert implements CorpusSelectionDialog.OnCorpusSelectedListener { 81521bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert public void onCorpusSelected(String corpusName) { 81621bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert setCorpus(corpusName); 817f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert updateSuggestions(getQuery()); 818f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert mQueryTextView.requestFocus(); 819dfe0df4a730c54bdc963b891f9a3080c38055ebbBjorn Bringert showInputMethodForQuery(); 820f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert } 8212617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert } 8222617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert 8232617a0177a6088d5aaf381263229bf5a62d2238dBjorn Bringert /** 8243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Listens for clicks on the voice search button. 8253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 8263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class VoiceSearchButtonClickListener implements View.OnClickListener { 8273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onClick(View view) { 8283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert onVoiceSearchClicked(); 8293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 8303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 8313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 83221bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert private class CorporaObserver extends DataSetObserver { 83321bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert @Override 83421bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert public void onChanged() { 83521bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert setCorpus(getCorpusName()); 83621bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert updateSuggestions(getQuery()); 83721bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert } 83821bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert } 83921bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert 8403d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney private static String ltrim(String text) { 8413d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney int start = 0; 8423d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney int length = text.length(); 8433d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney while (start < length && Character.isWhitespace(text.charAt(start))) { 8443d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney start++; 8453d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney } 8463d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney return start > 0 ? text.substring(start, length) : text; 8473d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney } 8483d382f0ca49a8150d504cf2629124a7f13175e1eBryan Mawhinney 8493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert} 850