SearchActivity.java revision 713194910648268c094fa81b81f40ce2f7e39333
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 19713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringertimport com.android.quicksearchbox.ui.SourceSelector; 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.ActivityNotFoundException; 28713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringertimport android.content.ComponentName; 293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.Intent; 303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.database.DataSetObserver; 313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.graphics.Rect; 323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.graphics.drawable.Animatable; 33d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinneyimport android.graphics.drawable.Drawable; 343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.os.Bundle; 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; 443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.widget.EditText; 453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.widget.ImageButton; 463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 47782dd228e78e9294692d639597f96c26283968bbBjorn Bringert// TODO: restore user query when using dpad to move up from top suggestion 48782dd228e78e9294692d639597f96c26283968bbBjorn Bringert// TODO: nicer progress animation. one per source? 49782dd228e78e9294692d639597f96c26283968bbBjorn Bringert// TODO: handle long clicks 50782dd228e78e9294692d639597f96c26283968bbBjorn Bringert// TODO: support action keys 51782dd228e78e9294692d639597f96c26283968bbBjorn Bringert// TODO: support IME search action 52782dd228e78e9294692d639597f96c26283968bbBjorn Bringert// TODO: allow typing everywhere in the UI 53185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: don't show new results until there is at least one, or it's done 553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: add timeout for source queries 563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: group refreshes that happen close to each other. 573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: use queryAfterZeroResults() 58782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 59782dd228e78e9294692d639597f96c26283968bbBjorn Bringert// TODO: use permission to get extended Genie suggestions 603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: support intent extras for source (e.g. launcher widget) 613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: support intent extras for initial state, e.g. query, selection 623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: make Config server-side configurable 633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: log impressions 643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert// TODO: use source ranking 653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/** 673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * The main activity for Quick Search Box. Shows the search UI. 683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpublic class SearchActivity extends Activity { 713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private static final boolean DBG = true; 733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private static final String TAG = "SearchActivity"; 743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // TODO: This is hidden in SearchManager 763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public final static String INTENT_ACTION_SEARCH_SETTINGS 773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert = "android.search.action.SEARCH_SETTINGS"; 783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 79713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private static final int REQUEST_SELECT_SOURCE = 0; 80713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 81185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert protected SuggestionsAdapter mSuggestionsAdapter; 82185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected EditText mQueryTextView; 843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected SuggestionsView mSuggestionsView; 863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected ImageButton mSearchGoButton; 883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected ImageButton mVoiceSearchButton; 89713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert protected SourceSelector mSourceSelector; 903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private Launcher mLauncher; 923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 93713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private Source mSource; 94713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private boolean mUpdateSuggestions; 95713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private Bundle mAppSearchData; 96713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private String mUserQuery; 97713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private boolean mSelectAll; 983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** Called when the activity is first created. */ 1003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 1013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onCreate(Bundle savedInstanceState) { 1023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "onCreate()"); 1033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onCreate(savedInstanceState); 104713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 105713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert // TODO: Use savedInstanceState to restore state 106713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSource = null; 107713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mUpdateSuggestions = true; 108713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mAppSearchData = null; 109713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mUserQuery = ""; 110713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSelectAll = false; 111713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 1123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert setContentView(R.layout.search_bar); 1133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 114d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney Config config = getConfig(); 115185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert SuggestionViewFactory viewFactory = getSuggestionViewFactory(); 116185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsAdapter = new SuggestionsAdapter(viewFactory); 117185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsAdapter 118185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert .setInitialSourceResultWaitMillis(config.getInitialSourceResultWaitMillis()); 119185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsAdapter 120185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert .setSourceResultPublishDelayMillis(config.getSourceResultPublishDelayMillis()); 121185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 1223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQueryTextView = (EditText) findViewById(R.id.search_src_text); 1233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSuggestionsView = (SuggestionsView) findViewById(R.id.suggestions); 124782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mSuggestionsView.setSuggestionClickListener(new ClickHandler()); 125782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mSuggestionsView.setInteractionListener(new InputMethodCloser()); 126713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSuggestionsView.setOnKeyListener(new SuggestionsViewKeyListener()); 1273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSearchGoButton = (ImageButton) findViewById(R.id.search_go_btn); 1293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mVoiceSearchButton = (ImageButton) findViewById(R.id.search_voice_btn); 130713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSourceSelector = (SourceSelector) findViewById(R.id.source_selector); 1313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Intent intent = getIntent(); 1333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // getIntent() currently always returns non-null, but the API does not guarantee 1343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // that it always will. 1353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (intent != null) { 136713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert setupFromIntent(intent); 1373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 138713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mLauncher = new Launcher(this, mAppSearchData); 1393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mVoiceSearchButton.setVisibility( 1403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mLauncher.isVoiceSearchAvailable() ? View.VISIBLE : View.GONE); 1413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 142782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mQueryTextView.addTextChangedListener(new SearchTextWatcher()); 143782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mQueryTextView.setOnKeyListener(new QueryTextViewKeyListener()); 144782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mQueryTextView.setOnFocusChangeListener(new SuggestListFocusListener()); 145782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 146782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mSearchGoButton.setOnClickListener(new SearchGoButtonClickListener()); 147782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mSearchGoButton.setOnKeyListener(new ButtonsKeyListener()); 148782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 149782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mVoiceSearchButton.setOnClickListener(new VoiceSearchButtonClickListener()); 150782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mVoiceSearchButton.setOnKeyListener(new ButtonsKeyListener()); 151713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 152713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert // Do this at the end, to avoid updating the list view when setSource() 153713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert // is called. 154713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSuggestionsView.setAdapter(mSuggestionsAdapter); 155713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 156713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert // Must be done after the source is set 157713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSourceSelector.setSearchInfo(new SearchInfo()); 158713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 159713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 160713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert @Override 161713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert protected void onActivityResult(int requestCode, int resultCode, Intent data) { 162713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert if (requestCode == REQUEST_SELECT_SOURCE) { 163713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert if (resultCode == RESULT_OK && data != null) { 164713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert setupFromIntent(data); 165713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 166713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 167713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 168713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 169713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private void setupFromIntent(Intent intent) { 170713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert if (DBG) Log.d(TAG, "setupFromIntent(" + intent.toUri(0) + ")"); 171713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert ComponentName sourceName = SourceSelector.getGlobalSearchComponent(intent); 172713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert setSource(sourceName); 173713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 174713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert String initialQuery = intent.getStringExtra(SearchManager.QUERY); 175713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert if (!TextUtils.isEmpty(initialQuery)) { 176713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mUserQuery = initialQuery; 177713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 178713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert // TODO: Declare an intent extra for selectAll 179713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mAppSearchData = intent.getBundleExtra(SearchManager.APP_DATA); 180713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 181713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 182713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private void setSource(ComponentName sourceName) { 183713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert if (sourceName == null) { 184713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSource = null; 185713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSuggestionsAdapter.setSource(null); 186713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } else { 187713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert SourceLookup sources = getSources(); 188713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSource = sources.getSourceByComponentName(sourceName); 189713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert if (mSource != null) { 190713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSuggestionsAdapter.setSource(sourceName); 191713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } else { 192713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert Log.w(TAG, "Unknown source " + sourceName); 193713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSuggestionsAdapter.setSource(null); 194713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 195713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 196713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert mSourceSelector.update(); 1973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private QsbApplication getQsbApplication() { 2003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return (QsbApplication) getApplication(); 2013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 203d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney private Config getConfig() { 204d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney return getQsbApplication().getConfig(); 205d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney } 206d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney 207713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private SourceLookup getSources() { 208713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert return getQsbApplication().getSources(); 209713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 210713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 2113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private ShortcutRepository getShortcutRepository() { 2123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getQsbApplication().getShortcutRepository(); 2133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private SuggestionsProvider getSuggestionsProvider() { 2163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getQsbApplication().getSuggestionsProvider(); 2173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 219185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert private SuggestionViewFactory getSuggestionViewFactory() { 220185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert return getQsbApplication().getSuggestionViewFactory(); 221185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert } 222185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 2233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 2243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onDestroy() { 2253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "onDestroy()"); 2263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onDestroy(); 227185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsView.setAdapter(null); // closes mSuggestionsAdapter 2283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 2313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onStart() { 2323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "onStart()"); 2333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onStart(); 2343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert setQuery(mUserQuery, mSelectAll); 2353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Only select everything the first time after creating the activity. 2363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSelectAll = false; 2373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert updateSuggestions(mUserQuery); 2383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 2413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onStop() { 2423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "onResume()"); 2433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Close all open suggestion cursors. The query will be redone in onStart() 2443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // if we come back to this activity. 245185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsAdapter.setSuggestions(null); 2463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onStop(); 2473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 250b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert protected void onResume() { 251b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert super.onResume(); 252b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert mQueryTextView.requestFocus(); 253b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert } 254b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert 255b32ee8f1b45c65daff18b40c0614cf18843b8c17Bjorn Bringert @Override 2563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean onCreateOptionsMenu(Menu menu) { 2573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super.onCreateOptionsMenu(menu); 2583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Intent settings = new Intent(INTENT_ACTION_SEARCH_SETTINGS); 2603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert settings.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 2613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Don't show activity chooser if there are multiple search settings activities, 2623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // e.g. from different QSB implementations. 2633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert settings.setPackage(this.getPackageName()); 2643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert menu.add(Menu.NONE, Menu.NONE, 0, R.string.menu_settings) 2653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert .setIcon(android.R.drawable.ic_menu_preferences).setAlphabeticShortcut('P') 2663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert .setIntent(settings); 2673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return true; 2693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 271713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert protected String getQuery() { 2723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert CharSequence q = mQueryTextView.getText(); 2733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return q == null ? "" : q.toString(); 2743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 2773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Restores the query entered by the user. 2783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 2793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void restoreUserQuery() { 2803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Restoring query to '" + mUserQuery + "'"); 2813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert setQuery(mUserQuery, false); 2823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 2853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Sets the text in the query box. Does not update the suggestions, 2863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * and does not change the saved user-entered query. 2873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * {@link #restoreUserQuery()} will restore the query to the last 2883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * user-entered query. 2893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 2903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void setQuery(String query, boolean selectAll) { 2913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mUpdateSuggestions = false; 2923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQueryTextView.setText(query); 2933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert setTextSelection(selectAll); 2943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mUpdateSuggestions = true; 2953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 2983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Sets the text selection in the query text view. 2993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 3003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * @param selectAll If {@code true}, selects the entire query. 3013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * If {@false}, no characters are selected, and the cursor is placed 3023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * at the end of the query. 3033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 3043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void setTextSelection(boolean selectAll) { 3053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (selectAll) { 3063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQueryTextView.setSelection(0, mQueryTextView.length()); 3073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else { 3083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQueryTextView.setSelection(mQueryTextView.length()); 3093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onSearchClicked() { 3133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String query = getQuery(); 3143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Search clicked, query=" + query); 3153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mLauncher.startWebSearch(query); 3163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onVoiceSearchClicked() { 3193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Voice Search clicked"); 3203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mLauncher.startVoiceSearch(); 3213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 323782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected boolean launchSuggestion(SuggestionPosition suggestion) { 324782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return launchSuggestion(suggestion, KeyEvent.KEYCODE_UNKNOWN, null); 325782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 326782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 327782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected boolean launchSuggestion(SuggestionPosition suggestion, 328782dd228e78e9294692d639597f96c26283968bbBjorn Bringert int actionKey, String actionMsg) { 329782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (DBG) Log.d(TAG, "Launching suggestion " + suggestion); 330782dd228e78e9294692d639597f96c26283968bbBjorn Bringert mLauncher.launchSuggestion(suggestion, actionKey, actionMsg); 3313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert getShortcutRepository().reportClick(suggestion); 3323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Update search widgets, since the top shortcuts can have changed. 3333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert SearchWidgetProvider.updateSearchWidgets(this); 3343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return true; 3353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 337782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected boolean launchSuggestionSecondary(SuggestionPosition suggestion, Rect target) { 3383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Clicked on suggestion icon " + suggestion); 3393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mLauncher.launchSuggestionSecondary(suggestion, target); 3403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert getShortcutRepository().reportClick(suggestion); 3413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return true; 3423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 344782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected boolean onSuggestionLongClicked(SuggestionPosition suggestion) { 345782dd228e78e9294692d639597f96c26283968bbBjorn Bringert SuggestionCursor sourceResult = suggestion.getSuggestion(); 3463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "Long clicked on suggestion " + sourceResult.getSuggestionText1()); 3473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return false; 3483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 350782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected void onSuggestionSelected(SuggestionPosition suggestion) { 351782dd228e78e9294692d639597f96c26283968bbBjorn Bringert SuggestionCursor sourceResult = suggestion.getSuggestion(); 3523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String displayQuery = sourceResult.getSuggestionDisplayQuery(); 3533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) { 3543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.d(TAG, "Selected suggestion " + sourceResult.getSuggestionText1() 3553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert + ",displayQuery="+ displayQuery); 3563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (TextUtils.isEmpty(displayQuery)) { 3583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert restoreUserQuery(); 3593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else { 3603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert setQuery(displayQuery, false); 3613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 364782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected boolean onSuggestionKeyDown(SuggestionPosition suggestion, 365782dd228e78e9294692d639597f96c26283968bbBjorn Bringert int keyCode, KeyEvent event) { 366782dd228e78e9294692d639597f96c26283968bbBjorn Bringert // Treat enter or search as a click 367782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH) { 368782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return launchSuggestion(suggestion); 369782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 370782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 371782dd228e78e9294692d639597f96c26283968bbBjorn Bringert // Handle source-specified action keys 372782dd228e78e9294692d639597f96c26283968bbBjorn Bringert String actionMsg = suggestion.getSuggestion().getActionKeyMsg(keyCode); 373782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (actionMsg != null) { 374782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return launchSuggestion(suggestion, keyCode, actionMsg); 375782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 376782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 377782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return false; 378782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 379782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 3803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void onSourceSelected() { 3813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "No suggestion selected"); 3823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert restoreUserQuery(); 3833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 385782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected int getSelectedPosition() { 386782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return mSuggestionsView.getSelectedPosition(); 387782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 388782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 389782dd228e78e9294692d639597f96c26283968bbBjorn Bringert protected SuggestionPosition getSelectedSuggestion() { 390782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return mSuggestionsView.getSelectedSuggestion(); 391782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 392782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 3933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Hides the input method. 3953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 3963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void hideInputMethod() { 3973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); 3983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (imm != null) { 3993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert imm.hideSoftInputFromWindow(mQueryTextView.getWindowToken(), 0); 4003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 4043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Hides the input method when the suggestions get focus. 4053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 4063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class SuggestListFocusListener implements OnFocusChangeListener { 4073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onFocusChange(View v, boolean focused) { 4083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (v == mQueryTextView) { 4093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (!focused) { 4103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert hideInputMethod(); 4113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else { 4123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // TODO: clear list selection? 4133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void startSearchProgress() { 4193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // TODO: Cache animation between calls? 4203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSearchGoButton.setImageResource(R.drawable.searching); 4213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Animatable animation = (Animatable) mSearchGoButton.getDrawable(); 4223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert animation.start(); 4233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void stopSearchProgress() { 426d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney Drawable animation = mSearchGoButton.getDrawable(); 427d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney if (animation instanceof Animatable) { 428d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney // TODO: Is this needed, or is it done automatically when the 429d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney // animation is removed? 430d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney ((Animatable) animation).stop(); 431d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney } 4323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSearchGoButton.setImageResource(R.drawable.ic_btn_search); 4333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private void updateSuggestions(String query) { 4363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert LatencyTracker latency = new LatencyTracker(TAG); 4373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Suggestions suggestions = getSuggestionsProvider().getSuggestions(query); 4383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert latency.addEvent("getSuggestions_done"); 4393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (!suggestions.isDone()) { 4403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert suggestions.registerDataSetObserver(new ProgressUpdater(suggestions)); 4413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert startSearchProgress(); 442d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney } else { 443d7a95801d20a9405b4ab9c9b4beecd106e880166Bryan Mawhinney stopSearchProgress(); 4443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 445185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert mSuggestionsAdapter.setSuggestions(suggestions); 4463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert latency.addEvent("shortcuts_shown"); 4473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert long userVisibleLatency = latency.getUserVisibleLatency(); 4483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) { 4493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.d(TAG, "User visible latency (shortcuts): " + userVisibleLatency + " ms."); 4503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 4543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Filters the suggestions list when the search text changes. 4553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 4563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class SearchTextWatcher implements TextWatcher { 4573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void afterTextChanged(Editable s) { 4583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mUpdateSuggestions) { 4593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String query = s == null ? "" : s.toString(); 4603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mUserQuery = query; 4613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert updateSuggestions(query); 4623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void beforeTextChanged(CharSequence s, int start, int count, int after) { 4663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onTextChanged(CharSequence s, int start, int before, int count) { 4693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 4733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Handles non-text keys in the query text view. 4743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 4753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class QueryTextViewKeyListener implements View.OnKeyListener { 4763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean onKey(View view, int keyCode, KeyEvent event) { 4773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Handle IME search action key 4783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) { 4793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert onSearchClicked(); 4803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return false; 4823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 485782dd228e78e9294692d639597f96c26283968bbBjorn Bringert /** 486782dd228e78e9294692d639597f96c26283968bbBjorn Bringert * Handles key events on the search and voice search buttons, 487782dd228e78e9294692d639597f96c26283968bbBjorn Bringert * by refocusing to EditText. 488782dd228e78e9294692d639597f96c26283968bbBjorn Bringert */ 489782dd228e78e9294692d639597f96c26283968bbBjorn Bringert private class ButtonsKeyListener implements View.OnKeyListener { 490782dd228e78e9294692d639597f96c26283968bbBjorn Bringert public boolean onKey(View v, int keyCode, KeyEvent event) { 491782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (!event.isSystem() && 492782dd228e78e9294692d639597f96c26283968bbBjorn Bringert (keyCode != KeyEvent.KEYCODE_DPAD_UP) && 493782dd228e78e9294692d639597f96c26283968bbBjorn Bringert (keyCode != KeyEvent.KEYCODE_DPAD_LEFT) && 494782dd228e78e9294692d639597f96c26283968bbBjorn Bringert (keyCode != KeyEvent.KEYCODE_DPAD_RIGHT) && 495782dd228e78e9294692d639597f96c26283968bbBjorn Bringert (keyCode != KeyEvent.KEYCODE_DPAD_CENTER)) { 496782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (mQueryTextView.requestFocus()) { 497782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return mQueryTextView.dispatchKeyEvent(event); 498782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 499782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 500782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return false; 501782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 502782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 503782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 504782dd228e78e9294692d639597f96c26283968bbBjorn Bringert /** 505782dd228e78e9294692d639597f96c26283968bbBjorn Bringert * Handles key events on the suggestions list view. 506782dd228e78e9294692d639597f96c26283968bbBjorn Bringert */ 507713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private class SuggestionsViewKeyListener implements View.OnKeyListener { 508782dd228e78e9294692d639597f96c26283968bbBjorn Bringert public boolean onKey(View v, int keyCode, KeyEvent event) { 509782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (event.getAction() == KeyEvent.ACTION_DOWN) { 510782dd228e78e9294692d639597f96c26283968bbBjorn Bringert SuggestionPosition suggestion = getSelectedSuggestion(); 511782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (suggestion != null) { 512782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return onSuggestionKeyDown(suggestion, keyCode, event); 513782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 514782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 515782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return false; 516782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 517782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 518782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 519185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert private class InputMethodCloser implements SuggestionsView.InteractionListener { 520185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert public void onInteraction() { 521185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert hideInputMethod(); 522185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert } 523185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert } 524185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert 525185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert private class ClickHandler implements SuggestionClickListener { 526713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert public void onSuggestionClicked(SuggestionPosition suggestion) { 527713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert launchSuggestion(suggestion); 5283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 530713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert public boolean onSuggestionLongClicked(SuggestionPosition suggestion) { 531713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert return SearchActivity.this.onSuggestionLongClicked(suggestion); 532713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 533713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 534713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert public void onSuggestionSelected(SuggestionPosition suggestion) { 535713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert SearchActivity.this.onSuggestionSelected(suggestion); 536782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 537782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 538713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert public void onSuggestionIconClicked(SuggestionPosition suggestion, Rect rect) { 539713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert launchSuggestionSecondary(suggestion, rect); 5403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 5443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Listens for clicks on the search button. 5453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 5463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class SearchGoButtonClickListener implements View.OnClickListener { 5473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onClick(View view) { 5483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert onSearchClicked(); 5493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 5533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Listens for clicks on the voice search button. 5543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 5553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class VoiceSearchButtonClickListener implements View.OnClickListener { 5563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onClick(View view) { 5573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert onVoiceSearchClicked(); 5583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 5623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Updates the progress bar when the suggestions adapter changes its progress. 5633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 5643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private class ProgressUpdater extends DataSetObserver { 5653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final Suggestions mSuggestions; 5663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public ProgressUpdater(Suggestions suggestions) { 5683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSuggestions = suggestions; 5693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 5723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void onChanged() { 5733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mSuggestions.isDone()) { 5743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert stopSearchProgress(); 5753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 578713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert 579713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert private class SearchInfo implements SourceSelector.SearchInfo { 580713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert public Bundle getAppSearchData() { 581713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert return mAppSearchData; 582713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 583713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert public Drawable getSourceIcon() { 584713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert if (mSource == null) { 585713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert return getSuggestionViewFactory().getGlobalSearchIcon(); 586713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } else { 587713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert return mSource.getSourceIcon(); 588713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 589713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 590713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert public String getQuery() { 591713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert return SearchActivity.this.getQuery(); 592713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 593713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert public ComponentName getSourceName() { 594713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert return mSource == null ? null : mSource.getComponentName(); 595713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 596713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert public void startActivity(Intent intent) throws ActivityNotFoundException { 597713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert startActivityForResult(intent, REQUEST_SELECT_SOURCE); 598713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 599713194910648268c094fa81b81f40ce2f7e39333Bjorn Bringert } 6003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert} 601