summaryrefslogtreecommitdiff
path: root/core/java/android/app/SearchDialog.java
diff options
context:
space:
mode:
authorAmith Yamasani <yamasani@google.com>2010-12-02 14:00:47 -0800
committerAmith Yamasani <yamasani@google.com>2010-12-03 11:18:25 -0800
commit968ec938399033d280b1648123104ac567f2a093 (patch)
tree1625adbcfbd8b4ab02b80aa071b6e72f3620c6fa /core/java/android/app/SearchDialog.java
parent189ee18d6c6483ad63cc864267328259e2e00b95 (diff)
Use SearchView in SearchDialog for legacy apps using the old model.
Bug: 3140925 Removed all the code from SearchDialog that is already in SearchView and moved more stuff into SearchView. SearchDialog layout changed to be more like a Holo.Light themed action mode. Search field is right justified and limited to 500dip. Zero query dropdown added to SearchView (causing some problems with Gmail, but that may be an existing issue that's only now showing up due to this change) Holo.Light search views assets still need to be updated, as the contrast is too low.
Diffstat (limited to 'core/java/android/app/SearchDialog.java')
-rw-r--r--core/java/android/app/SearchDialog.java1018
1 files changed, 98 insertions, 920 deletions
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 0c280f99e50b..4d19b622f492 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -17,12 +17,6 @@
package android.app;
-import static android.app.SuggestionsAdapter.getColumnString;
-
-import java.util.WeakHashMap;
-import java.util.concurrent.atomic.AtomicLong;
-
-import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -30,21 +24,15 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
-import android.provider.Browser;
import android.speech.RecognizerIntent;
-import android.text.Editable;
import android.text.InputType;
import android.text.TextUtils;
-import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
@@ -55,18 +43,15 @@ import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
-import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
-import android.widget.AdapterView;
import android.widget.AutoCompleteTextView;
-import android.widget.Button;
-import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.ListView;
+import android.widget.SearchView;
import android.widget.TextView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.AdapterView.OnItemSelectedListener;
+
+import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicLong;
/**
* Search dialog. This is controlled by the
@@ -74,32 +59,28 @@ import android.widget.AdapterView.OnItemSelectedListener;
*
* @hide
*/
-public class SearchDialog extends Dialog implements OnItemClickListener, OnItemSelectedListener {
+public class SearchDialog extends Dialog {
// Debugging support
private static final boolean DBG = false;
private static final String LOG_TAG = "SearchDialog";
- private static final boolean DBG_LOG_TIMING = false;
private static final String INSTANCE_KEY_COMPONENT = "comp";
private static final String INSTANCE_KEY_APPDATA = "data";
- private static final String INSTANCE_KEY_STORED_APPDATA = "sData";
private static final String INSTANCE_KEY_USER_QUERY = "uQry";
-
+
// The string used for privateImeOptions to identify to the IME that it should not show
// a microphone button since one already exists in the search dialog.
private static final String IME_OPTION_NO_MICROPHONE = "nm";
- private static final int SEARCH_PLATE_LEFT_PADDING_GLOBAL = 12;
private static final int SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL = 7;
// views & widgets
private TextView mBadgeLabel;
private ImageView mAppIcon;
- private SearchAutoComplete mSearchAutoComplete;
- private Button mGoButton;
- private ImageButton mVoiceButton;
+ private AutoCompleteTextView mSearchAutoComplete;
private View mSearchPlate;
+ private SearchView mSearchView;
private Drawable mWorkingSpinner;
// interaction with searchable application
@@ -107,30 +88,15 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
private ComponentName mLaunchComponent;
private Bundle mAppSearchData;
private Context mActivityContext;
- private SearchManager mSearchManager;
// For voice searching
private final Intent mVoiceWebSearchIntent;
private final Intent mVoiceAppSearchIntent;
- // support for AutoCompleteTextView suggestions display
- private SuggestionsAdapter mSuggestionsAdapter;
-
- // Whether to rewrite queries when selecting suggestions
- private static final boolean REWRITE_QUERIES = true;
-
// The query entered by the user. This is not changed when selecting a suggestion
// that modifies the contents of the text field. But if the user then edits
// the suggestion, the resulting string is saved.
private String mUserQuery;
- // The query passed in when opening the SearchDialog. Used in the browser
- // case to determine whether the user has edited the query.
- private String mInitialQuery;
-
- // A weak map of drawables we've gotten from other packages, so we don't load them
- // more than once.
- private final WeakHashMap<String, Drawable.ConstantState> mOutsideDrawablesCache =
- new WeakHashMap<String, Drawable.ConstantState>();
// Last known IME options value for the search edit text.
private int mSearchAutoCompleteImeOptions;
@@ -160,7 +126,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mSearchManager = searchManager;
}
/**
@@ -196,30 +161,24 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// get the view elements for local access
SearchBar searchBar = (SearchBar) findViewById(com.android.internal.R.id.search_bar);
searchBar.setSearchDialog(this);
-
- mBadgeLabel = (TextView) findViewById(com.android.internal.R.id.search_badge);
- mSearchAutoComplete = (SearchAutoComplete)
- findViewById(com.android.internal.R.id.search_src_text);
+ mSearchView = (SearchView) findViewById(com.android.internal.R.id.search_view);
+ mSearchView.setSubmitButtonEnabled(true);
+ mSearchView.setOnCloseListener(mOnCloseListener);
+ mSearchView.setOnQueryChangeListener(mOnQueryChangeListener);
+ mSearchView.setOnSuggestionSelectionListener(mOnSuggestionSelectionListener);
+
+ // TODO: Move the badge logic to SearchView or move the badge to search_bar.xml
+ mBadgeLabel = (TextView) mSearchView.findViewById(com.android.internal.R.id.search_badge);
+ mSearchAutoComplete = (AutoCompleteTextView)
+ mSearchView.findViewById(com.android.internal.R.id.search_src_text);
mAppIcon = (ImageView) findViewById(com.android.internal.R.id.search_app_icon);
- mGoButton = (Button) findViewById(com.android.internal.R.id.search_go_btn);
- mVoiceButton = (ImageButton) findViewById(com.android.internal.R.id.search_voice_btn);
- mSearchPlate = findViewById(com.android.internal.R.id.search_plate);
+ mSearchPlate = mSearchView.findViewById(com.android.internal.R.id.search_plate);
mWorkingSpinner = getContext().getResources().
getDrawable(com.android.internal.R.drawable.search_spinner);
mSearchAutoComplete.setCompoundDrawablesWithIntrinsicBounds(
null, null, mWorkingSpinner, null);
setWorking(false);
- // attach listeners
- mSearchAutoComplete.addTextChangedListener(mTextWatcher);
- mSearchAutoComplete.setOnKeyListener(mTextKeyListener);
- mSearchAutoComplete.setOnItemClickListener(this);
- mSearchAutoComplete.setOnItemSelectedListener(this);
- mGoButton.setOnClickListener(mGoButtonClickListener);
- mGoButton.setOnKeyListener(mButtonsKeyListener);
- mVoiceButton.setOnClickListener(mVoiceButtonClickListener);
- mVoiceButton.setOnKeyListener(mButtonsKeyListener);
-
// pre-hide all the extraneous elements
mBadgeLabel.setVisibility(View.GONE);
@@ -256,7 +215,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
return false;
}
- mInitialQuery = initialQuery == null ? "" : initialQuery;
// finally, load the user's initial text (which may trigger suggestions)
setUserQuery(initialQuery);
if (selectInitialQuery) {
@@ -296,6 +254,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// Recreate the search bar view every time the dialog is shown, to get rid
// of any bad state in the AutoCompleteTextView etc
createContentView();
+ mSearchView.setSearchableInfo(mSearchable);
show();
}
@@ -326,14 +285,11 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
getContext().unregisterReceiver(mConfChangeListener);
- closeSuggestionsAdapter();
-
// dump extra memory we're hanging on to
mLaunchComponent = null;
mAppSearchData = null;
mSearchable = null;
mUserQuery = null;
- mInitialQuery = null;
}
/**
@@ -349,20 +305,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
/**
- * Closes and gets rid of the suggestions adapter.
- */
- private void closeSuggestionsAdapter() {
- // remove the adapter from the autocomplete first, to avoid any updates
- // when we drop the cursor
- mSearchAutoComplete.setAdapter((SuggestionsAdapter)null);
- // close any leftover cursor
- if (mSuggestionsAdapter != null) {
- mSuggestionsAdapter.close();
- }
- mSuggestionsAdapter = null;
- }
-
- /**
* Save the minimal set of data necessary to recreate the search
*
* @return A bundle with the state of the dialog, or {@code null} if the search
@@ -385,8 +327,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
/**
* Restore the state of the dialog from a previously saved bundle.
*
- * TODO: go through this and make sure that it saves everything that is saved
- *
* @param savedInstanceState The state of the dialog previously saved by
* {@link #onSaveInstanceState()}.
*/
@@ -404,21 +344,18 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
return;
}
}
-
+
/**
* Called after resources have changed, e.g. after screen rotation or locale change.
*/
public void onConfigurationChanged() {
if (mSearchable != null && isShowing()) {
// Redraw (resources may have changed)
- updateSearchButton();
updateSearchAppIcon();
updateSearchBadge();
- updateQueryHint();
if (isLandscapeMode(getContext())) {
mSearchAutoComplete.ensureImeVisible(true);
}
- mSearchAutoComplete.showDropDownAfterLayout();
}
}
@@ -434,11 +371,8 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
if (mSearchable != null) {
mDecor.setVisibility(View.VISIBLE);
updateSearchAutoComplete();
- updateSearchButton();
updateSearchAppIcon();
updateSearchBadge();
- updateQueryHint();
- updateVoiceButton(TextUtils.isEmpty(mUserQuery));
// In order to properly configure the input method (if one is being used), we
// need to let it know if we'll be providing suggestions. Although it would be
@@ -474,68 +408,26 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
* Updates the auto-complete text view.
*/
private void updateSearchAutoComplete() {
- // close any existing suggestions adapter
- closeSuggestionsAdapter();
-
- mSearchAutoComplete.setDropDownAnimationStyle(0); // no animation
- mSearchAutoComplete.setThreshold(mSearchable.getSuggestThreshold());
// we dismiss the entire dialog instead
mSearchAutoComplete.setDropDownDismissedOnCompletion(false);
-
- mSearchAutoComplete.setForceIgnoreOutsideTouch(true);
-
- // attach the suggestions adapter, if suggestions are available
- // The existence of a suggestions authority is the proxy for "suggestions available here"
- if (mSearchable.getSuggestAuthority() != null) {
- mSuggestionsAdapter = new SuggestionsAdapter(getContext(), this, mSearchable,
- mOutsideDrawablesCache);
- mSearchAutoComplete.setAdapter(mSuggestionsAdapter);
- }
- }
-
- private void updateSearchButton() {
- String textLabel = null;
- Drawable iconLabel = null;
- int textId = mSearchable.getSearchButtonText();
- if (isBrowserSearch()){
- iconLabel = getContext().getResources()
- .getDrawable(com.android.internal.R.drawable.ic_btn_search_go);
- } else if (textId != 0) {
- textLabel = mActivityContext.getResources().getString(textId);
- } else {
- iconLabel = getContext().getResources().
- getDrawable(com.android.internal.R.drawable.ic_btn_search);
- }
- mGoButton.setText(textLabel);
- mGoButton.setCompoundDrawablesWithIntrinsicBounds(iconLabel, null, null, null);
+ mSearchAutoComplete.setForceIgnoreOutsideTouch(false);
}
private void updateSearchAppIcon() {
- if (isBrowserSearch()) {
- mAppIcon.setImageResource(0);
- mAppIcon.setVisibility(View.GONE);
- mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_GLOBAL,
- mSearchPlate.getPaddingTop(),
- mSearchPlate.getPaddingRight(),
- mSearchPlate.getPaddingBottom());
- } else {
- PackageManager pm = getContext().getPackageManager();
- Drawable icon;
- try {
- ActivityInfo info = pm.getActivityInfo(mLaunchComponent, 0);
- icon = pm.getApplicationIcon(info.applicationInfo);
- if (DBG) Log.d(LOG_TAG, "Using app-specific icon");
- } catch (NameNotFoundException e) {
- icon = pm.getDefaultActivityIcon();
- Log.w(LOG_TAG, mLaunchComponent + " not found, using generic app icon");
- }
- mAppIcon.setImageDrawable(icon);
- mAppIcon.setVisibility(View.VISIBLE);
- mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL,
- mSearchPlate.getPaddingTop(),
- mSearchPlate.getPaddingRight(),
- mSearchPlate.getPaddingBottom());
+ PackageManager pm = getContext().getPackageManager();
+ Drawable icon;
+ try {
+ ActivityInfo info = pm.getActivityInfo(mLaunchComponent, 0);
+ icon = pm.getApplicationIcon(info.applicationInfo);
+ if (DBG)
+ Log.d(LOG_TAG, "Using app-specific icon");
+ } catch (NameNotFoundException e) {
+ icon = pm.getDefaultActivityIcon();
+ Log.w(LOG_TAG, mLaunchComponent + " not found, using generic app icon");
}
+ mAppIcon.setImageDrawable(icon);
+ mAppIcon.setVisibility(View.VISIBLE);
+ mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL, mSearchPlate.getPaddingTop(), mSearchPlate.getPaddingRight(), mSearchPlate.getPaddingBottom());
}
/**
@@ -546,7 +438,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
int visibility = View.GONE;
Drawable icon = null;
CharSequence text = null;
-
+
// optionally show one or the other.
if (mSearchable.useBadgeIcon()) {
icon = mActivityContext.getResources().getDrawable(mSearchable.getIconId());
@@ -557,71 +449,12 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
visibility = View.VISIBLE;
if (DBG) Log.d(LOG_TAG, "Using badge label: " + mSearchable.getLabelId());
}
-
+
mBadgeLabel.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
mBadgeLabel.setText(text);
mBadgeLabel.setVisibility(visibility);
}
- /**
- * Update the hint in the query text field.
- */
- private void updateQueryHint() {
- if (isShowing()) {
- String hint = null;
- if (mSearchable != null) {
- int hintId = mSearchable.getHintId();
- if (hintId != 0) {
- hint = mActivityContext.getString(hintId);
- }
- }
- mSearchAutoComplete.setHint(hint);
- }
- }
-
- /**
- * Update the visibility of the voice button. There are actually two voice search modes,
- * either of which will activate the button.
- * @param empty whether the search query text field is empty. If it is, then the other
- * criteria apply to make the voice button visible. Otherwise the voice button will not
- * be visible - i.e., if the user has typed a query, remove the voice button.
- */
- private void updateVoiceButton(boolean empty) {
- int visibility = View.GONE;
- if ((mAppSearchData == null || !mAppSearchData.getBoolean(
- SearchManager.DISABLE_VOICE_SEARCH, false))
- && mSearchable.getVoiceSearchEnabled() && empty) {
- Intent testIntent = null;
- if (mSearchable.getVoiceSearchLaunchWebSearch()) {
- testIntent = mVoiceWebSearchIntent;
- } else if (mSearchable.getVoiceSearchLaunchRecognizer()) {
- testIntent = mVoiceAppSearchIntent;
- }
- if (testIntent != null) {
- ResolveInfo ri = getContext().getPackageManager().
- resolveActivity(testIntent, PackageManager.MATCH_DEFAULT_ONLY);
- if (ri != null) {
- visibility = View.VISIBLE;
- }
- }
- }
- mVoiceButton.setVisibility(visibility);
- }
-
- /** Called by SuggestionsAdapter when the cursor contents changed. */
- void onDataSetChanged() {
- if (mSearchAutoComplete != null && mSuggestionsAdapter != null) {
- mSearchAutoComplete.onFilterComplete(mSuggestionsAdapter.getCount());
- }
- }
-
- /**
- * Hack to determine whether this is the browser, so we can adjust the UI.
- */
- private boolean isBrowserSearch() {
- return mLaunchComponent.flattenToShortString().startsWith("com.android.browser/");
- }
-
/*
* Listeners of various types
*/
@@ -642,7 +475,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// Let Dialog handle events outside the window while the pop-up is showing.
return super.onTouchEvent(event);
}
-
+
private boolean isOutOfBounds(View v, MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
@@ -651,336 +484,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
|| (x > (v.getWidth()+slop))
|| (y > (v.getHeight()+slop));
}
-
- /**
- * Dialog's OnKeyListener implements various search-specific functionality
- *
- * @param keyCode This is the keycode of the typed key, and is the same value as
- * found in the KeyEvent parameter.
- * @param event The complete event record for the typed key
- *
- * @return Return true if the event was handled here, or false if not.
- */
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (DBG) Log.d(LOG_TAG, "onKeyDown(" + keyCode + "," + event + ")");
- if (mSearchable == null) {
- return false;
- }
-
- // if it's an action specified by the searchable activity, launch the
- // entered query with the action key
- SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode);
- if ((actionKey != null) && (actionKey.getQueryActionMsg() != null)) {
- launchQuerySearch(keyCode, actionKey.getQueryActionMsg());
- return true;
- }
-
- return super.onKeyDown(keyCode, event);
- }
-
- /**
- * Callback to watch the textedit field for empty/non-empty
- */
- private TextWatcher mTextWatcher = new TextWatcher() {
-
- public void beforeTextChanged(CharSequence s, int start, int before, int after) { }
-
- public void onTextChanged(CharSequence s, int start,
- int before, int after) {
- if (DBG_LOG_TIMING) {
- dbgLogTiming("onTextChanged()");
- }
- if (mSearchable == null) {
- return;
- }
- if (!mSearchAutoComplete.isPerformingCompletion()) {
- // The user changed the query, remember it.
- mUserQuery = s == null ? "" : s.toString();
- }
- updateWidgetState();
- // Always want to show the microphone if the context is voice.
- // Also show the microphone if this is a browser search and the
- // query matches the initial query.
- updateVoiceButton(mSearchAutoComplete.isEmpty()
- || (isBrowserSearch() && mInitialQuery.equals(mUserQuery))
- || (mAppSearchData != null && mAppSearchData.getBoolean(
- SearchManager.CONTEXT_IS_VOICE)));
- }
-
- public void afterTextChanged(Editable s) {
- if (mSearchable == null) {
- return;
- }
- if (mSearchable.autoUrlDetect() && !mSearchAutoComplete.isPerformingCompletion()) {
- // The user changed the query, check if it is a URL and if so change the search
- // button in the soft keyboard to the 'Go' button.
- int options = (mSearchAutoComplete.getImeOptions() & (~EditorInfo.IME_MASK_ACTION))
- | EditorInfo.IME_ACTION_GO;
- if (options != mSearchAutoCompleteImeOptions) {
- mSearchAutoCompleteImeOptions = options;
- mSearchAutoComplete.setImeOptions(options);
- // This call is required to update the soft keyboard UI with latest IME flags.
- mSearchAutoComplete.setInputType(mSearchAutoComplete.getInputType());
- }
- }
- }
- };
-
- /**
- * Enable/Disable the go button based on edit text state (any text?)
- */
- private void updateWidgetState() {
- // enable the button if we have one or more non-space characters
- boolean enabled = !mSearchAutoComplete.isEmpty();
- if (isBrowserSearch()) {
- // In the browser, we hide the search button when there is no text,
- // or if the text matches the initial query.
- if (enabled && !mInitialQuery.equals(mUserQuery)) {
- mSearchAutoComplete.setBackgroundResource(
- com.android.internal.R.drawable.textfield_search);
- mGoButton.setVisibility(View.VISIBLE);
- // Just to be sure
- mGoButton.setEnabled(true);
- mGoButton.setFocusable(true);
- } else {
- mSearchAutoComplete.setBackgroundResource(
- com.android.internal.R.drawable.textfield_search_empty);
- mGoButton.setVisibility(View.GONE);
- }
- } else {
- // Elsewhere we just disable the button
- mGoButton.setEnabled(enabled);
- mGoButton.setFocusable(enabled);
- }
- }
-
- /**
- * React to typing in the GO search button by refocusing to EditText.
- * Continue typing the query.
- */
- View.OnKeyListener mButtonsKeyListener = new View.OnKeyListener() {
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- // guard against possible race conditions
- if (mSearchable == null) {
- return false;
- }
-
- if (!event.isSystem() &&
- (keyCode != KeyEvent.KEYCODE_DPAD_UP) &&
- (keyCode != KeyEvent.KEYCODE_DPAD_LEFT) &&
- (keyCode != KeyEvent.KEYCODE_DPAD_RIGHT) &&
- (keyCode != KeyEvent.KEYCODE_DPAD_CENTER)) {
- // restore focus and give key to EditText ...
- if (mSearchAutoComplete.requestFocus()) {
- return mSearchAutoComplete.dispatchKeyEvent(event);
- }
- }
-
- return false;
- }
- };
-
- /**
- * React to a click in the GO button by launching a search.
- */
- View.OnClickListener mGoButtonClickListener = new View.OnClickListener() {
- public void onClick(View v) {
- // guard against possible race conditions
- if (mSearchable == null) {
- return;
- }
- launchQuerySearch();
- }
- };
-
- /**
- * React to a click in the voice search button.
- */
- View.OnClickListener mVoiceButtonClickListener = new View.OnClickListener() {
- public void onClick(View v) {
- // guard against possible race conditions
- if (mSearchable == null) {
- return;
- }
- SearchableInfo searchable = mSearchable;
- try {
- if (searchable.getVoiceSearchLaunchWebSearch()) {
- Intent webSearchIntent = createVoiceWebSearchIntent(mVoiceWebSearchIntent,
- searchable);
- getContext().startActivity(webSearchIntent);
- } else if (searchable.getVoiceSearchLaunchRecognizer()) {
- Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent,
- searchable);
- getContext().startActivity(appSearchIntent);
- }
- } catch (ActivityNotFoundException e) {
- // Should not happen, since we check the availability of
- // voice search before showing the button. But just in case...
- Log.w(LOG_TAG, "Could not find voice search activity");
- }
- dismiss();
- }
- };
-
- /**
- * Create and return an Intent that can launch the voice search activity for web search.
- */
- private Intent createVoiceWebSearchIntent(Intent baseIntent, SearchableInfo searchable) {
- Intent voiceIntent = new Intent(baseIntent);
- ComponentName searchActivity = searchable.getSearchActivity();
- voiceIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,
- searchActivity == null ? null : searchActivity.flattenToShortString());
- return voiceIntent;
- }
-
- /**
- * Create and return an Intent that can launch the voice search activity, perform a specific
- * voice transcription, and forward the results to the searchable activity.
- *
- * @param baseIntent The voice app search intent to start from
- * @return A completely-configured intent ready to send to the voice search activity
- */
- private Intent createVoiceAppSearchIntent(Intent baseIntent, SearchableInfo searchable) {
- ComponentName searchActivity = searchable.getSearchActivity();
-
- // create the necessary intent to set up a search-and-forward operation
- // in the voice search system. We have to keep the bundle separate,
- // because it becomes immutable once it enters the PendingIntent
- Intent queryIntent = new Intent(Intent.ACTION_SEARCH);
- queryIntent.setComponent(searchActivity);
- PendingIntent pending = PendingIntent.getActivity(
- getContext(), 0, queryIntent, PendingIntent.FLAG_ONE_SHOT);
-
- // Now set up the bundle that will be inserted into the pending intent
- // when it's time to do the search. We always build it here (even if empty)
- // because the voice search activity will always need to insert "QUERY" into
- // it anyway.
- Bundle queryExtras = new Bundle();
- if (mAppSearchData != null) {
- queryExtras.putBundle(SearchManager.APP_DATA, mAppSearchData);
- }
-
- // Now build the intent to launch the voice search. Add all necessary
- // extras to launch the voice recognizer, and then all the necessary extras
- // to forward the results to the searchable activity
- Intent voiceIntent = new Intent(baseIntent);
-
- // Add all of the configuration options supplied by the searchable's metadata
- String languageModel = RecognizerIntent.LANGUAGE_MODEL_FREE_FORM;
- String prompt = null;
- String language = null;
- int maxResults = 1;
- Resources resources = mActivityContext.getResources();
- if (searchable.getVoiceLanguageModeId() != 0) {
- languageModel = resources.getString(searchable.getVoiceLanguageModeId());
- }
- if (searchable.getVoicePromptTextId() != 0) {
- prompt = resources.getString(searchable.getVoicePromptTextId());
- }
- if (searchable.getVoiceLanguageId() != 0) {
- language = resources.getString(searchable.getVoiceLanguageId());
- }
- if (searchable.getVoiceMaxResults() != 0) {
- maxResults = searchable.getVoiceMaxResults();
- }
- voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, languageModel);
- voiceIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, prompt);
- voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language);
- voiceIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, maxResults);
- voiceIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,
- searchActivity == null ? null : searchActivity.flattenToShortString());
-
- // Add the values that configure forwarding the results
- voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT, pending);
- voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT_BUNDLE, queryExtras);
-
- return voiceIntent;
- }
-
- /**
- * Corrects http/https typo errors in the given url string, and if the protocol specifier was
- * not present defaults to http.
- *
- * @param inUrl URL to check and fix
- * @return fixed URL string.
- */
- private String fixUrl(String inUrl) {
- if (inUrl.startsWith("http://") || inUrl.startsWith("https://"))
- return inUrl;
-
- if (inUrl.startsWith("http:") || inUrl.startsWith("https:")) {
- if (inUrl.startsWith("http:/") || inUrl.startsWith("https:/")) {
- inUrl = inUrl.replaceFirst("/", "//");
- } else {
- inUrl = inUrl.replaceFirst(":", "://");
- }
- }
-
- if (inUrl.indexOf("://") == -1) {
- inUrl = "http://" + inUrl;
- }
-
- return inUrl;
- }
-
- /**
- * React to the user typing "enter" or other hardwired keys while typing in the search box.
- * This handles these special keys while the edit box has focus.
- */
- View.OnKeyListener mTextKeyListener = new View.OnKeyListener() {
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- // guard against possible race conditions
- if (mSearchable == null) {
- return false;
- }
-
- if (DBG_LOG_TIMING) dbgLogTiming("doTextKey()");
- if (DBG) {
- Log.d(LOG_TAG, "mTextListener.onKey(" + keyCode + "," + event
- + "), selection: " + mSearchAutoComplete.getListSelection());
- }
-
- // If a suggestion is selected, handle enter, search key, and action keys
- // as presses on the selected suggestion
- if (mSearchAutoComplete.isPopupShowing() &&
- mSearchAutoComplete.getListSelection() != ListView.INVALID_POSITION) {
- return onSuggestionsKey(v, keyCode, event);
- }
-
- // If there is text in the query box, handle enter, and action keys
- // The search key is handled by the dialog's onKeyDown().
- if (!mSearchAutoComplete.isEmpty()) {
- if (keyCode == KeyEvent.KEYCODE_ENTER
- && event.getAction() == KeyEvent.ACTION_UP) {
- v.cancelLongPress();
-
- // If this is a url entered by the user & we displayed the 'Go' button which
- // the user clicked, launch the url instead of using it as a search query.
- if (mSearchable.autoUrlDetect() &&
- (mSearchAutoCompleteImeOptions & EditorInfo.IME_MASK_ACTION)
- == EditorInfo.IME_ACTION_GO) {
- Uri uri = Uri.parse(fixUrl(mSearchAutoComplete.getText().toString()));
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- launchIntent(intent);
- } else {
- // Launch as a regular search.
- launchQuerySearch();
- }
- return true;
- }
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode);
- if ((actionKey != null) && (actionKey.getQueryActionMsg() != null)) {
- launchQuerySearch(keyCode, actionKey.getQueryActionMsg());
- return true;
- }
- }
- }
- return false;
- }
- };
@Override
public void hide() {
@@ -997,78 +500,11 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
super.hide();
}
-
- /**
- * React to the user typing while in the suggestions list. First, check for action
- * keys. If not handled, try refocusing regular characters into the EditText.
- */
- private boolean onSuggestionsKey(View v, int keyCode, KeyEvent event) {
- // guard against possible race conditions (late arrival after dismiss)
- if (mSearchable == null) {
- return false;
- }
- if (mSuggestionsAdapter == null) {
- return false;
- }
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- if (DBG_LOG_TIMING) {
- dbgLogTiming("onSuggestionsKey()");
- }
-
- // First, check for enter or search (both of which we'll treat as a "click")
- if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH) {
- int position = mSearchAutoComplete.getListSelection();
- return launchSuggestion(position);
- }
-
- // Next, check for left/right moves, which we use to "return" the user to the edit view
- if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
- // give "focus" to text editor, with cursor at the beginning if
- // left key, at end if right key
- // TODO: Reverse left/right for right-to-left languages, e.g. Arabic
- int selPoint = (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) ?
- 0 : mSearchAutoComplete.length();
- mSearchAutoComplete.setSelection(selPoint);
- mSearchAutoComplete.setListSelection(0);
- mSearchAutoComplete.clearListSelection();
- mSearchAutoComplete.ensureImeVisible(true);
-
- return true;
- }
-
- // Next, check for an "up and out" move
- if (keyCode == KeyEvent.KEYCODE_DPAD_UP
- && 0 == mSearchAutoComplete.getListSelection()) {
- restoreUserQuery();
- // let ACTV complete the move
- return false;
- }
-
- // Next, check for an "action key"
- SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode);
- if ((actionKey != null) &&
- ((actionKey.getSuggestActionMsg() != null) ||
- (actionKey.getSuggestActionMsgColumn() != null))) {
- // launch suggestion using action key column
- int position = mSearchAutoComplete.getListSelection();
- if (position != ListView.INVALID_POSITION) {
- Cursor c = mSuggestionsAdapter.getCursor();
- if (c.moveToPosition(position)) {
- final String actionMsg = getActionKeyMessage(c, actionKey);
- if (actionMsg != null && (actionMsg.length() > 0)) {
- return launchSuggestion(position, keyCode, actionMsg);
- }
- }
- }
- }
- }
- return false;
- }
/**
* Launch a search for the text in the query text field.
*/
- public void launchQuerySearch() {
+ public void launchQuerySearch() {
launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null);
}
@@ -1080,50 +516,12 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
* @param actionMsg The message for the action key that was pressed,
* or <code>null</code> if none.
*/
- protected void launchQuerySearch(int actionKey, String actionMsg) {
+ protected void launchQuerySearch(int actionKey, String actionMsg) {
String query = mSearchAutoComplete.getText().toString();
String action = Intent.ACTION_SEARCH;
- Intent intent = createIntent(action, null, null, query,
- actionKey, actionMsg);
+ Intent intent = createIntent(action, null, null, query, actionKey, actionMsg);
launchIntent(intent);
}
-
- /**
- * Launches an intent based on a suggestion.
- *
- * @param position The index of the suggestion to create the intent from.
- * @return true if a successful launch, false if could not (e.g. bad position).
- */
- protected boolean launchSuggestion(int position) {
- return launchSuggestion(position, KeyEvent.KEYCODE_UNKNOWN, null);
- }
-
- /**
- * Launches an intent based on a suggestion.
- *
- * @param position The index of the suggestion to create the intent from.
- * @param actionKey The key code of the action key that was pressed,
- * or {@link KeyEvent#KEYCODE_UNKNOWN} if none.
- * @param actionMsg The message for the action key that was pressed,
- * or <code>null</code> if none.
- * @return true if a successful launch, false if could not (e.g. bad position).
- */
- protected boolean launchSuggestion(int position, int actionKey, String actionMsg) {
- if (mSuggestionsAdapter == null) {
- return false;
- }
- Cursor c = mSuggestionsAdapter.getCursor();
- if ((c != null) && c.moveToPosition(position)) {
-
- Intent intent = createIntentFromSuggestion(c, actionKey, actionMsg);
-
- // launch the intent
- launchIntent(intent);
-
- return true;
- }
- return false;
- }
/**
* Launches an intent, including any special intent handling.
@@ -1149,21 +547,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
/**
- * If the intent is to open an HTTP or HTTPS URL, we set
- * {@link Browser#EXTRA_APPLICATION_ID} so that any existing browser window that
- * has been opened by us for the same URL will be reused.
- */
- private void setBrowserApplicationId(Intent intent) {
- Uri data = intent.getData();
- if (Intent.ACTION_VIEW.equals(intent.getAction()) && data != null) {
- String scheme = data.getScheme();
- if (scheme != null && scheme.startsWith("http")) {
- intent.putExtra(Browser.EXTRA_APPLICATION_ID, data.toString());
- }
- }
- }
-
- /**
* Sets the list item selection in the AutoCompleteTextView's ListView.
*/
public void setListSelection(int index) {
@@ -1171,62 +554,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
/**
- * When a particular suggestion has been selected, perform the various lookups required
- * to use the suggestion. This includes checking the cursor for suggestion-specific data,
- * and/or falling back to the XML for defaults; It also creates REST style Uri data when
- * the suggestion includes a data id.
- *
- * @param c The suggestions cursor, moved to the row of the user's selection
- * @param actionKey The key code of the action key that was pressed,
- * or {@link KeyEvent#KEYCODE_UNKNOWN} if none.
- * @param actionMsg The message for the action key that was pressed,
- * or <code>null</code> if none.
- * @return An intent for the suggestion at the cursor's position.
- */
- private Intent createIntentFromSuggestion(Cursor c, int actionKey, String actionMsg) {
- try {
- // use specific action if supplied, or default action if supplied, or fixed default
- String action = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_ACTION);
-
- if (action == null) {
- action = mSearchable.getSuggestIntentAction();
- }
- if (action == null) {
- action = Intent.ACTION_SEARCH;
- }
-
- // use specific data if supplied, or default data if supplied
- String data = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_DATA);
- if (data == null) {
- data = mSearchable.getSuggestIntentData();
- }
- // then, if an ID was provided, append it.
- if (data != null) {
- String id = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID);
- if (id != null) {
- data = data + "/" + Uri.encode(id);
- }
- }
- Uri dataUri = (data == null) ? null : Uri.parse(data);
-
- String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY);
- String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
-
- return createIntent(action, dataUri, extraData, query, actionKey, actionMsg);
- } catch (RuntimeException e ) {
- int rowNum;
- try { // be really paranoid now
- rowNum = c.getPosition();
- } catch (RuntimeException e2 ) {
- rowNum = -1;
- }
- Log.w(LOG_TAG, "Search Suggestions cursor at row " + rowNum +
- " returned exception" + e.toString());
- return null;
- }
- }
-
- /**
* Constructs an intent from the given information and the search dialog state.
*
* @param action Intent action.
@@ -1271,30 +598,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
/**
- * For a given suggestion and a given cursor row, get the action message. If not provided
- * by the specific row/column, also check for a single definition (for the action key).
- *
- * @param c The cursor providing suggestions
- * @param actionKey The actionkey record being examined
- *
- * @return Returns a string, or null if no action key message for this suggestion
- */
- private static String getActionKeyMessage(Cursor c, SearchableInfo.ActionKeyInfo actionKey) {
- String result = null;
- // check first in the cursor data, for a suggestion-specific message
- final String column = actionKey.getSuggestActionMsgColumn();
- if (column != null) {
- result = SuggestionsAdapter.getColumnString(c, column);
- }
- // If the cursor didn't give us a message, see if there's a single message defined
- // for the actionkey (for all suggestions)
- if (result == null) {
- result = actionKey.getSuggestActionMsg();
- }
- return result;
- }
-
- /**
* The root element in the search bar layout. This is a custom view just to override
* the handling of the back button.
*/
@@ -1315,21 +618,22 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
/**
- * Overrides the handling of the back key to move back to the previous sources or dismiss
- * the search dialog, instead of dismissing the input method.
+ * Overrides the handling of the back key to move back to the previous
+ * sources or dismiss the search dialog, instead of dismissing the input
+ * method.
*/
@Override
public boolean dispatchKeyEventPreIme(KeyEvent event) {
- if (DBG) Log.d(LOG_TAG, "onKeyPreIme(" + event + ")");
+ if (DBG)
+ Log.d(LOG_TAG, "onKeyPreIme(" + event + ")");
if (mSearchDialog != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
KeyEvent.DispatcherState state = getKeyDispatcherState();
if (state != null) {
- if (event.getAction() == KeyEvent.ACTION_DOWN
- && event.getRepeatCount() == 0) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
state.startTracking(event, this);
return true;
- } else if (event.getAction() == KeyEvent.ACTION_UP
- && !event.isCanceled() && state.isTracking(event)) {
+ } else if (event.getAction() == KeyEvent.ACTION_UP && !event.isCanceled()
+ && state.isTracking(event)) {
mSearchDialog.onBackPressed();
return true;
}
@@ -1339,86 +643,8 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
}
- /**
- * Local subclass for AutoCompleteTextView.
- */
- public static class SearchAutoComplete extends AutoCompleteTextView {
-
- private int mThreshold;
-
- public SearchAutoComplete(Context context) {
- super(context);
- mThreshold = getThreshold();
- }
-
- public SearchAutoComplete(Context context, AttributeSet attrs) {
- super(context, attrs);
- mThreshold = getThreshold();
- }
-
- public SearchAutoComplete(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mThreshold = getThreshold();
- }
-
- @Override
- public void setThreshold(int threshold) {
- super.setThreshold(threshold);
- mThreshold = threshold;
- }
-
- /**
- * Returns true if the text field is empty, or contains only whitespace.
- */
- private boolean isEmpty() {
- return TextUtils.getTrimmedLength(getText()) == 0;
- }
-
- /**
- * We override this method to avoid replacing the query box text
- * when a suggestion is clicked.
- */
- @Override
- protected void replaceText(CharSequence text) {
- }
-
- /**
- * We override this method to avoid an extra onItemClick being called on the
- * drop-down's OnItemClickListener by {@link AutoCompleteTextView#onKeyUp(int, KeyEvent)}
- * when an item is clicked with the trackball.
- */
- @Override
- public void performCompletion() {
- }
-
- /**
- * We override this method to be sure and show the soft keyboard if appropriate when
- * the TextView has focus.
- */
- @Override
- public void onWindowFocusChanged(boolean hasWindowFocus) {
- super.onWindowFocusChanged(hasWindowFocus);
-
- if (hasWindowFocus) {
- InputMethodManager inputManager = (InputMethodManager)
- getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- inputManager.showSoftInput(this, 0);
- // If in landscape mode, then make sure that
- // the ime is in front of the dropdown.
- if (isLandscapeMode(getContext())) {
- ensureImeVisible(true);
- }
- }
- }
-
- /**
- * We override this method so that we can allow a threshold of zero, which ACTV does not.
- */
- @Override
- public boolean enoughToFilter() {
- return mThreshold <= 0 || super.enoughToFilter();
- }
-
+ private boolean isEmpty(AutoCompleteTextView actv) {
+ return TextUtils.getTrimmedLength(actv.getText()) == 0;
}
@Override
@@ -1435,106 +661,58 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
cancel();
}
- /**
- * Implements OnItemClickListener
- */
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- if (DBG) Log.d(LOG_TAG, "onItemClick() position " + position);
- launchSuggestion(position);
+ private boolean onClosePressed() {
+ // Dismiss the dialog if close button is pressed when there's no query text
+ if (isEmpty(mSearchAutoComplete)) {
+ dismiss();
+ return true;
+ }
+
+ return false;
}
- /**
- * Implements OnItemSelectedListener
- */
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- if (DBG) Log.d(LOG_TAG, "onItemSelected() position " + position);
- // A suggestion has been selected, rewrite the query if possible,
- // otherwise the restore the original query.
- if (REWRITE_QUERIES) {
- rewriteQueryFromSuggestion(position);
- }
- }
-
- /**
- * Implements OnItemSelectedListener
- */
- public void onNothingSelected(AdapterView<?> parent) {
- if (DBG) Log.d(LOG_TAG, "onNothingSelected()");
- }
-
- /**
- * Query rewriting.
- */
-
- private void rewriteQueryFromSuggestion(int position) {
- Cursor c = mSuggestionsAdapter.getCursor();
- if (c == null) {
- return;
- }
- if (c.moveToPosition(position)) {
- // Get the new query from the suggestion.
- CharSequence newQuery = mSuggestionsAdapter.convertToString(c);
- if (newQuery != null) {
- // The suggestion rewrites the query.
- if (DBG) Log.d(LOG_TAG, "Rewriting query to '" + newQuery + "'");
- // Update the text field, without getting new suggestions.
- setQuery(newQuery);
- } else {
- // The suggestion does not rewrite the query, restore the user's query.
- if (DBG) Log.d(LOG_TAG, "Suggestion gives no rewrite, restoring user query.");
- restoreUserQuery();
- }
- } else {
- // We got a bad position, restore the user's query.
- Log.w(LOG_TAG, "Bad suggestion position: " + position);
- restoreUserQuery();
- }
- }
-
- /**
- * Restores the query entered by the user if needed.
- */
- private void restoreUserQuery() {
- if (DBG) Log.d(LOG_TAG, "Restoring query to '" + mUserQuery + "'");
- setQuery(mUserQuery);
- }
-
- /**
- * Sets the text in the query box, without updating the suggestions.
- */
- private void setQuery(CharSequence query) {
- mSearchAutoComplete.setText(query, false);
- if (query != null) {
- mSearchAutoComplete.setSelection(query.length());
- }
- }
-
- /**
- * Sets the text in the query box, updating the suggestions.
- */
- private void setUserQuery(String query) {
- if (query == null) {
- query = "";
- }
- mUserQuery = query;
- mSearchAutoComplete.setText(query);
- mSearchAutoComplete.setSelection(query.length());
- }
+ private final SearchView.OnCloseListener mOnCloseListener = new SearchView.OnCloseListener() {
- /**
- * Debugging Support
- */
+ public boolean onClose() {
+ return onClosePressed();
+ }
+ };
+
+ private final SearchView.OnQueryChangeListener mOnQueryChangeListener =
+ new SearchView.OnQueryChangeListener() {
+
+ public boolean onSubmitQuery(String query) {
+ dismiss();
+ return false;
+ }
+
+ public boolean onQueryTextChanged(String newText) {
+ return false;
+ }
+ };
+
+ private final SearchView.OnSuggestionSelectionListener mOnSuggestionSelectionListener =
+ new SearchView.OnSuggestionSelectionListener() {
+
+ public boolean onSuggestionSelected(int position) {
+ return false;
+ }
+
+ public boolean onSuggestionClicked(int position) {
+ dismiss();
+ return false;
+ }
+ };
/**
- * For debugging only, sample the millisecond clock and log it.
- * Uses AtomicLong so we can use in multiple threads
+ * Sets the text in the query box, updating the suggestions.
*/
- private AtomicLong mLastLogTime = new AtomicLong(SystemClock.uptimeMillis());
- private void dbgLogTiming(final String caller) {
- long millis = SystemClock.uptimeMillis();
- long oldTime = mLastLogTime.getAndSet(millis);
- long delta = millis - oldTime;
- final String report = millis + " (+" + delta + ") ticks for Search keystroke in " + caller;
- Log.d(LOG_TAG,report);
+ private void setUserQuery(String query) {
+ if (query == null) {
+ query = "";
+ }
+ mUserQuery = query;
+ mSearchAutoComplete.setText(query);
+ mSearchAutoComplete.setSelection(query.length());
}
}