SearchActivity.java revision 9ad03a750a66b26441a19ff54b6057729c145eae
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 199ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringertimport com.android.quicksearchbox.ui.SearchSourceSelector; 20185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionClickListener; 21185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionViewFactory; 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; 27713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringertimport android.content.ComponentName; 283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.Intent; 293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.database.DataSetObserver; 303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.graphics.Rect; 313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.graphics.drawable.Animatable; 32d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinneyimport android.graphics.drawable.Drawable; 333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.os.Bundle; 343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.Editable; 353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.TextUtils; 363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.TextWatcher; 373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.util.Log; 383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.KeyEvent; 393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.Menu; 403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.View; 413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.View.OnFocusChangeListener; 423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.inputmethod.InputMethodManager; 433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.widget.EditText; 443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.widget.ImageButton; 453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 46782dd228e78e9294692d639597f96c26283968bbBjorn Bringert// TODO: restore user query when using dpad to move up from top suggestion 47782dd228e78e9294692d639597f96c26283968bbBjorn Bringert// TODO: nicer progress animation. one per source? 48782dd228e78e9294692d639597f96c26283968bbBjorn Bringert// TODO: handle long clicks 49782dd228e78e9294692d639597f96c26283968bbBjorn Bringert// TODO: support action keys 50782dd228e78e9294692d639597f96c26283968bbBjorn Bringert// TODO: support IME search action 51782dd228e78e9294692d639597f96c26283968bbBjorn Bringert// TODO: allow typing everywhere in the UI 52185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: don't show new results until there is at least one, or it's done 543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: add timeout for source queries 553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: group refreshes that happen close to each other. 563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: use queryAfterZeroResults() 57782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 58782dd228e78e9294692d639597f96c26283968bbBjorn Bringert// TODO: use permission to get extended Genie suggestions 593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: support intent extras for source (e.g. launcher widget) 603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: support intent extras for initial state, e.g. query, selection 613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: make Config server-side configurable 623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: log impressions 633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: use source ranking 643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/** 663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * The main activity for Quick Search Box. Shows the search UI. 673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpublic class SearchActivity extends Activity { 703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private static final boolean DBG = true; 723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private static final String TAG = "SearchActivity"; 733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // TODO: This is hidden in SearchManager 753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public final static String INTENT_ACTION_SEARCH_SETTINGS 763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert = "android.search.action.SEARCH_SETTINGS"; 773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 789ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert public static final String EXTRA_KEY_SEARCH_SOURCE 799ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert = "search_source"; 809ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert 819ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // Keys for the saved instance state. 829ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert private static final String INSTANCE_KEY_SOURCE = "source"; 839ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert private static final String INSTANCE_KEY_USER_QUERY = "query"; 84713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 85185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert protected SuggestionsAdapter mSuggestionsAdapter; 86185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected EditText mQueryTextView; 883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected SuggestionsView mSuggestionsView; 903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected ImageButton mSearchGoButton; 923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected ImageButton mVoiceSearchButton; 939ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert protected SearchSourceSelector mSourceSelector; 943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private Launcher mLauncher; 963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 979ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert private ComponentName mSourceName; 98713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private boolean mUpdateSuggestions; 99713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private String mUserQuery; 100713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private boolean mSelectAll; 1013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** Called when the activity is first created. */ 1033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 1043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onCreate(Bundle savedInstanceState) { 1053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "onCreate()"); 1063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onCreate(savedInstanceState); 107713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 1083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert setContentView(R.layout.search_bar); 1093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 110d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney Config config = getConfig(); 111185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert SuggestionViewFactory viewFactory = getSuggestionViewFactory(); 112185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsAdapter = new SuggestionsAdapter(viewFactory); 113185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsAdapter 114185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert .setInitialSourceResultWaitMillis(config.getInitialSourceResultWaitMillis()); 115185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsAdapter 116185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert .setSourceResultPublishDelayMillis(config.getSourceResultPublishDelayMillis()); 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()); 121782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mSuggestionsView.setInteractionListener(new InputMethodCloser()); 122713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSuggestionsView.setOnKeyListener(new SuggestionsViewKeyListener()); 1233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSearchGoButton = (ImageButton) findViewById(R.id.search_go_btn); 1253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mVoiceSearchButton = (ImageButton) findViewById(R.id.search_voice_btn); 1269ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mSourceSelector = new SearchSourceSelector(findViewById(R.id.search_source_selector)); 1273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1289ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mLauncher = new Launcher(this); 1293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mVoiceSearchButton.setVisibility( 1303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mLauncher.isVoiceSearchAvailable() ? View.VISIBLE : View.GONE); 1313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 132782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mQueryTextView.addTextChangedListener(new SearchTextWatcher()); 133782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mQueryTextView.setOnKeyListener(new QueryTextViewKeyListener()); 134782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mQueryTextView.setOnFocusChangeListener(new SuggestListFocusListener()); 135782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 136782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mSearchGoButton.setOnClickListener(new SearchGoButtonClickListener()); 137782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mSearchGoButton.setOnKeyListener(new ButtonsKeyListener()); 138782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 139782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mVoiceSearchButton.setOnClickListener(new VoiceSearchButtonClickListener()); 140782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mVoiceSearchButton.setOnKeyListener(new ButtonsKeyListener()); 141713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 1429ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mUpdateSuggestions = true; 1439ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert 1449ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // First get setup from intent 1459ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert Intent intent = getIntent(); 1469ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setupFromIntent(intent); 1479ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // Then restore any saved instance state 1489ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert restoreInstanceState(savedInstanceState); 1499ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert 150713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert // Do this at the end, to avoid updating the list view when setSource() 151713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert // is called. 152713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSuggestionsView.setAdapter(mSuggestionsAdapter); 1539ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert } 154713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 1559ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert @Override 1569ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert protected void onNewIntent(Intent intent) { 1579ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setIntent(intent); 1589ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setupFromIntent(intent); 1599ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert } 1609ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert 1619ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert protected void restoreInstanceState(Bundle savedInstanceState) { 1629ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert if (savedInstanceState == null) return; 1639ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert ComponentName sourceName = savedInstanceState.getParcelable(INSTANCE_KEY_SOURCE); 1649ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert String query = savedInstanceState.getString(INSTANCE_KEY_USER_QUERY); 1659ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setSource(getSourceByComponentName(sourceName)); 1669ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setUserQuery(query); 167713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 168713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 169713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert @Override 1709ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert protected void onSaveInstanceState(Bundle outState) { 1719ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert super.onSaveInstanceState(outState); 1729ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // We don't save appSearchData, since we always get the value 1739ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // from the intent and the user can't change it. 1749ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert outState.putParcelable(INSTANCE_KEY_SOURCE, mSourceName); 1759ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert outState.putString(INSTANCE_KEY_USER_QUERY, mUserQuery); 176713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 177713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 178713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private void setupFromIntent(Intent intent) { 179713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert if (DBG) Log.d(TAG, "setupFromIntent(" + intent.toUri(0) + ")"); 1809ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert Source source = getSourceByName(intent.getStringExtra(EXTRA_KEY_SEARCH_SOURCE)); 1819ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setSource(source); 1829ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // TODO: Should this be SearchManager.INITIAL_QUERY? 1839ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setUserQuery(intent.getStringExtra(SearchManager.QUERY)); 1849ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // TODO: Expose SearchManager.SELECT_INITIAL_QUERY 1859ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mSelectAll = false; 1869ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setAppSearchData(intent.getBundleExtra(SearchManager.APP_DATA)); 1879ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert } 1889ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert 1899ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert private Source getSourceByName(String sourceNameStr) { 1909ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert if (sourceNameStr == null) return null; 1919ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert ComponentName sourceName = ComponentName.unflattenFromString(sourceNameStr); 1929ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert if (sourceName == null) { 1939ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert Log.w(TAG, "Malformed source name: " + sourceName); 1949ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert return null; 1959ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert } 1969ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert return getSourceByComponentName(sourceName); 1979ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert } 198713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 1999ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert private Source getSourceByComponentName(ComponentName sourceName) { 2009ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert Source source = getSources().getSourceByComponentName(sourceName); 2019ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert if (source == null) { 2029ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert Log.w(TAG, "Unknown source " + sourceName); 2039ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert return null; 204713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 2059ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert return source; 206713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 207713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 2089ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert private void setSource(Source source) { 2099ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mSourceName = source == null ? null : source.getComponentName(); 2109ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert Drawable sourceIcon; 2119ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert if (source == null) { 2129ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert sourceIcon = getSuggestionViewFactory().getGlobalSearchIcon(); 213713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } else { 2149ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert sourceIcon = source.getSourceIcon(); 215713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 2169ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mSuggestionsAdapter.setSource(mSourceName); 2179ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mSourceSelector.setSource(mSourceName); 2189ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mSourceSelector.setSourceIcon(sourceIcon); 2193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private QsbApplication getQsbApplication() { 2223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return (QsbApplication) getApplication(); 2233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 225d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney private Config getConfig() { 226d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney return getQsbApplication().getConfig(); 227d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney } 228d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney 229713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private SourceLookup getSources() { 230713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert return getQsbApplication().getSources(); 231713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 232713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 2333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private ShortcutRepository getShortcutRepository() { 2343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getQsbApplication().getShortcutRepository(); 2353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private SuggestionsProvider getSuggestionsProvider() { 2383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getQsbApplication().getSuggestionsProvider(); 2393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 241185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert private SuggestionViewFactory getSuggestionViewFactory() { 242185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert return getQsbApplication().getSuggestionViewFactory(); 243185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert } 244185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 2453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 2463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onDestroy() { 2473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "onDestroy()"); 2483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onDestroy(); 249185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsView.setAdapter(null); // closes mSuggestionsAdapter 2503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 2533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onStop() { 2549ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert if (DBG) Log.d(TAG, "onStop()"); 2559ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // Close all open suggestion cursors. The query will be redone in onResume() 2563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // if we come back to this activity. 257185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsAdapter.setSuggestions(null); 2583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onStop(); 2593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 262b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert protected void onResume() { 2639ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert if (DBG) Log.d(TAG, "onResume()"); 264b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert super.onResume(); 2659ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setQuery(mUserQuery, mSelectAll); 2669ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert // Only select everything the first time after creating the activity. 2679ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mSelectAll = false; 2689ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert updateSuggestions(mUserQuery); 269b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert mQueryTextView.requestFocus(); 270b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert } 271b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert 272b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert @Override 2733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean onCreateOptionsMenu(Menu menu) { 2743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onCreateOptionsMenu(menu); 2753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Intent settings = new Intent(INTENT_ACTION_SEARCH_SETTINGS); 2773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert settings.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 2783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Don't show activity chooser if there are multiple search settings activities, 2793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // e.g. from different QSB implementations. 2803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert settings.setPackage(this.getPackageName()); 2813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert menu.add(Menu.NONE, Menu.NONE, 0, R.string.menu_settings) 2823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert .setIcon(android.R.drawable.ic_menu_preferences).setAlphabeticShortcut('P') 2833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert .setIntent(settings); 2843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return true; 2863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2889ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert /** 2899ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert * Sets the query as typed by the user. Does not update the suggestions 2909ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert * or the text in the query box. 2919ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert */ 2929ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert protected void setUserQuery(String userQuery) { 2939ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert if (userQuery == null) userQuery = ""; 2949ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mUserQuery = userQuery; 2959ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mSourceSelector.setQuery(mUserQuery); 2969ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert } 2979ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert 2989ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert protected void setAppSearchData(Bundle appSearchData) { 2999ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mLauncher.setAppSearchData(appSearchData); 3009ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert mSourceSelector.setAppSearchData(appSearchData); 3019ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert } 3029ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert 303713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert protected String getQuery() { 3043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert CharSequence q = mQueryTextView.getText(); 3053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return q == null ? "" : q.toString(); 3063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Restores the query entered by the user. 3103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 3113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void restoreUserQuery() { 3123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Restoring query to '" + mUserQuery + "'"); 3133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert setQuery(mUserQuery, false); 3143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Sets the text in the query box. Does not update the suggestions, 3183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * and does not change the saved user-entered query. 3193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * {@link #restoreUserQuery()} will restore the query to the last 3203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * user-entered query. 3213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 3223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void setQuery(String query, boolean selectAll) { 3233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mUpdateSuggestions = false; 3243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQueryTextView.setText(query); 3253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert setTextSelection(selectAll); 3263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mUpdateSuggestions = true; 3273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Sets the text selection in the query text view. 3313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 3323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * @param selectAll If {@code true}, selects the entire query. 3333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * If {@false}, no characters are selected, and the cursor is placed 3343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * at the end of the query. 3353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 3363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void setTextSelection(boolean selectAll) { 3373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (selectAll) { 3383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQueryTextView.setSelection(0, mQueryTextView.length()); 3393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else { 3403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQueryTextView.setSelection(mQueryTextView.length()); 3413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onSearchClicked() { 3453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String query = getQuery(); 3463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Search clicked, query=" + query); 3473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mLauncher.startWebSearch(query); 3483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onVoiceSearchClicked() { 3513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Voice Search clicked"); 3523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mLauncher.startVoiceSearch(); 3533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 355782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected boolean launchSuggestion(SuggestionPosition suggestion) { 356782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return launchSuggestion(suggestion, KeyEvent.KEYCODE_UNKNOWN, null); 357782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 358782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 359782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected boolean launchSuggestion(SuggestionPosition suggestion, 360782dd228e78e9294692d639597f96c26283968bbBjorn Bringert int actionKey, String actionMsg) { 361782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (DBG) Log.d(TAG, "Launching suggestion " + suggestion); 362782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mLauncher.launchSuggestion(suggestion, actionKey, actionMsg); 3633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert getShortcutRepository().reportClick(suggestion); 3643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Update search widgets, since the top shortcuts can have changed. 3653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert SearchWidgetProvider.updateSearchWidgets(this); 3663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return true; 3673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 369782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected boolean launchSuggestionSecondary(SuggestionPosition suggestion, Rect target) { 3703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Clicked on suggestion icon " + suggestion); 3713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mLauncher.launchSuggestionSecondary(suggestion, target); 3723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert getShortcutRepository().reportClick(suggestion); 3733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return true; 3743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 376782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected boolean onSuggestionLongClicked(SuggestionPosition suggestion) { 377782dd228e78e9294692d639597f96c26283968bbBjorn Bringert SuggestionCursor sourceResult = suggestion.getSuggestion(); 3783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Long clicked on suggestion " + sourceResult.getSuggestionText1()); 3793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return false; 3803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 382782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected void onSuggestionSelected(SuggestionPosition suggestion) { 383782dd228e78e9294692d639597f96c26283968bbBjorn Bringert SuggestionCursor sourceResult = suggestion.getSuggestion(); 3843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String displayQuery = sourceResult.getSuggestionDisplayQuery(); 3853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) { 3863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.d(TAG, "Selected suggestion " + sourceResult.getSuggestionText1() 3873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert + ",displayQuery="+ displayQuery); 3883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (TextUtils.isEmpty(displayQuery)) { 3903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert restoreUserQuery(); 3913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else { 3923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert setQuery(displayQuery, false); 3933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 396782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected boolean onSuggestionKeyDown(SuggestionPosition suggestion, 397782dd228e78e9294692d639597f96c26283968bbBjorn Bringert int keyCode, KeyEvent event) { 398782dd228e78e9294692d639597f96c26283968bbBjorn Bringert // Treat enter or search as a click 399782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH) { 400782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return launchSuggestion(suggestion); 401782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 402782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 403782dd228e78e9294692d639597f96c26283968bbBjorn Bringert // Handle source-specified action keys 404782dd228e78e9294692d639597f96c26283968bbBjorn Bringert String actionMsg = suggestion.getSuggestion().getActionKeyMsg(keyCode); 405782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (actionMsg != null) { 406782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return launchSuggestion(suggestion, keyCode, actionMsg); 407782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 408782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 409782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return false; 410782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 411782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 4123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onSourceSelected() { 4133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "No suggestion selected"); 4143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert restoreUserQuery(); 4153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 417782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected int getSelectedPosition() { 418782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return mSuggestionsView.getSelectedPosition(); 419782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 420782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 421782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected SuggestionPosition getSelectedSuggestion() { 422782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return mSuggestionsView.getSelectedSuggestion(); 423782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 424782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 4253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 4263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Hides the input method. 4273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 4283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void hideInputMethod() { 4293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); 4303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (imm != null) { 4313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert imm.hideSoftInputFromWindow(mQueryTextView.getWindowToken(), 0); 4323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 4363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Hides the input method when the suggestions get focus. 4373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 4383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class SuggestListFocusListener implements OnFocusChangeListener { 4393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onFocusChange(View v, boolean focused) { 4403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (v == mQueryTextView) { 4413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (!focused) { 4423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert hideInputMethod(); 4433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else { 4443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // TODO: clear list selection? 4453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void startSearchProgress() { 4513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // TODO: Cache animation between calls? 4523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSearchGoButton.setImageResource(R.drawable.searching); 4533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Animatable animation = (Animatable) mSearchGoButton.getDrawable(); 4543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert animation.start(); 4553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void stopSearchProgress() { 458d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney Drawable animation = mSearchGoButton.getDrawable(); 459d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney if (animation instanceof Animatable) { 460d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney // TODO: Is this needed, or is it done automatically when the 461d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney // animation is removed? 462d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney ((Animatable) animation).stop(); 463d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney } 4643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSearchGoButton.setImageResource(R.drawable.ic_btn_search); 4653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void updateSuggestions(String query) { 4683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert LatencyTracker latency = new LatencyTracker(TAG); 4693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Suggestions suggestions = getSuggestionsProvider().getSuggestions(query); 4703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert latency.addEvent("getSuggestions_done"); 4713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (!suggestions.isDone()) { 4723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert suggestions.registerDataSetObserver(new ProgressUpdater(suggestions)); 4733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert startSearchProgress(); 474d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney } else { 475d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney stopSearchProgress(); 4763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 477185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsAdapter.setSuggestions(suggestions); 4783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert latency.addEvent("shortcuts_shown"); 4793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert long userVisibleLatency = latency.getUserVisibleLatency(); 4803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) { 4813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.d(TAG, "User visible latency (shortcuts): " + userVisibleLatency + " ms."); 4823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 4863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Filters the suggestions list when the search text changes. 4873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 4883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class SearchTextWatcher implements TextWatcher { 4893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void afterTextChanged(Editable s) { 4903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mUpdateSuggestions) { 4913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String query = s == null ? "" : s.toString(); 4929ad03a750a66b26441a19ff54b6057729c145eaeBjorn Bringert setUserQuery(query); 4933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert updateSuggestions(query); 4943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void beforeTextChanged(CharSequence s, int start, int count, int after) { 4983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onTextChanged(CharSequence s, int start, int before, int count) { 5013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 5053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Handles non-text keys in the query text view. 5063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 5073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class QueryTextViewKeyListener implements View.OnKeyListener { 5083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean onKey(View view, int keyCode, KeyEvent event) { 5093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Handle IME search action key 5103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) { 5113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert onSearchClicked(); 5123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return false; 5143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 517782dd228e78e9294692d639597f96c26283968bbBjorn Bringert /** 518782dd228e78e9294692d639597f96c26283968bbBjorn Bringert * Handles key events on the search and voice search buttons, 519782dd228e78e9294692d639597f96c26283968bbBjorn Bringert * by refocusing to EditText. 520782dd228e78e9294692d639597f96c26283968bbBjorn Bringert */ 521782dd228e78e9294692d639597f96c26283968bbBjorn Bringert private class ButtonsKeyListener implements View.OnKeyListener { 522782dd228e78e9294692d639597f96c26283968bbBjorn Bringert public boolean onKey(View v, int keyCode, KeyEvent event) { 523782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (!event.isSystem() && 524782dd228e78e9294692d639597f96c26283968bbBjorn Bringert (keyCode != KeyEvent.KEYCODE_DPAD_UP) && 525782dd228e78e9294692d639597f96c26283968bbBjorn Bringert (keyCode != KeyEvent.KEYCODE_DPAD_LEFT) && 526782dd228e78e9294692d639597f96c26283968bbBjorn Bringert (keyCode != KeyEvent.KEYCODE_DPAD_RIGHT) && 527782dd228e78e9294692d639597f96c26283968bbBjorn Bringert (keyCode != KeyEvent.KEYCODE_DPAD_CENTER)) { 528782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (mQueryTextView.requestFocus()) { 529782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return mQueryTextView.dispatchKeyEvent(event); 530782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 531782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 532782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return false; 533782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 534782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 535782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 536782dd228e78e9294692d639597f96c26283968bbBjorn Bringert /** 537782dd228e78e9294692d639597f96c26283968bbBjorn Bringert * Handles key events on the suggestions list view. 538782dd228e78e9294692d639597f96c26283968bbBjorn Bringert */ 539713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private class SuggestionsViewKeyListener implements View.OnKeyListener { 540782dd228e78e9294692d639597f96c26283968bbBjorn Bringert public boolean onKey(View v, int keyCode, KeyEvent event) { 541782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (event.getAction() == KeyEvent.ACTION_DOWN) { 542782dd228e78e9294692d639597f96c26283968bbBjorn Bringert SuggestionPosition suggestion = getSelectedSuggestion(); 543782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (suggestion != null) { 544782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return onSuggestionKeyDown(suggestion, keyCode, event); 545782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 546782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 547782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return false; 548782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 549782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 550782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 551185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert private class InputMethodCloser implements SuggestionsView.InteractionListener { 552185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert public void onInteraction() { 553185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert hideInputMethod(); 554185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert } 555185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert } 556185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 557185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert private class ClickHandler implements SuggestionClickListener { 558713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert public void onSuggestionClicked(SuggestionPosition suggestion) { 559713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert launchSuggestion(suggestion); 5603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 562713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert public boolean onSuggestionLongClicked(SuggestionPosition suggestion) { 563713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert return SearchActivity.this.onSuggestionLongClicked(suggestion); 564713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 565713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 566713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert public void onSuggestionSelected(SuggestionPosition suggestion) { 567713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert SearchActivity.this.onSuggestionSelected(suggestion); 568782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 569782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 570713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert public void onSuggestionIconClicked(SuggestionPosition suggestion, Rect rect) { 571713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert launchSuggestionSecondary(suggestion, rect); 5723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 5763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Listens for clicks on the search button. 5773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 5783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class SearchGoButtonClickListener implements View.OnClickListener { 5793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onClick(View view) { 5803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert onSearchClicked(); 5813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 5853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Listens for clicks on the voice search button. 5863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 5873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class VoiceSearchButtonClickListener implements View.OnClickListener { 5883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onClick(View view) { 5893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert onVoiceSearchClicked(); 5903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 5943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Updates the progress bar when the suggestions adapter changes its progress. 5953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 5963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class ProgressUpdater extends DataSetObserver { 5973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final Suggestions mSuggestions; 5983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public ProgressUpdater(Suggestions suggestions) { 6003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSuggestions = suggestions; 6013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 6043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onChanged() { 6053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mSuggestions.isDone()) { 6063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert stopSearchProgress(); 6073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 6093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 610713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 6113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert} 612