import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.util.Log;
-import android.util.TypedValue;
import android.view.CollapsibleActionView;
import android.view.KeyEvent;
import android.view.LayoutInflater;
*/
private static final String IME_OPTION_NO_MICROPHONE = "nm";
- private final SearchAutoComplete mQueryTextView;
+ private final SearchAutoComplete mSearchSrcTextView;
private final View mSearchEditFrame;
private final View mSearchPlate;
private final View mSubmitArea;
private final ImageView mSearchButton;
- private final ImageView mSubmitButton;
+ private final ImageView mGoButton;
private final ImageView mCloseButton;
private final ImageView mVoiceButton;
- private final ImageView mSearchHintIcon;
private final View mDropDownAnchor;
- private final int mSearchIconResId;
+
+ /** Icon optionally displayed when the SearchView is collapsed. */
+ private final ImageView mCollapsedIcon;
+
+ /** Drawable used as an EditText hint. */
+ private final Drawable mSearchHintIcon;
// Resources used by SuggestionsAdapter to display suggestions.
private final int mSuggestionRowLayout;
attrs, R.styleable.SearchView, defStyleAttr, defStyleRes);
final LayoutInflater inflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
- final int layoutResId = a.getResourceId(R.styleable.SearchView_layout, R.layout.search_view);
+ final int layoutResId = a.getResourceId(
+ R.styleable.SearchView_layout, R.layout.search_view);
inflater.inflate(layoutResId, this, true);
- mQueryTextView = (SearchAutoComplete) findViewById(R.id.search_src_text);
- mQueryTextView.setSearchView(this);
+ mSearchSrcTextView = (SearchAutoComplete) findViewById(R.id.search_src_text);
+ mSearchSrcTextView.setSearchView(this);
mSearchEditFrame = findViewById(R.id.search_edit_frame);
mSearchPlate = findViewById(R.id.search_plate);
mSubmitArea = findViewById(R.id.submit_area);
mSearchButton = (ImageView) findViewById(R.id.search_button);
- mSubmitButton = (ImageView) findViewById(R.id.search_go_btn);
+ mGoButton = (ImageView) findViewById(R.id.search_go_btn);
mCloseButton = (ImageView) findViewById(R.id.search_close_btn);
mVoiceButton = (ImageView) findViewById(R.id.search_voice_btn);
- mSearchHintIcon = (ImageView) findViewById(R.id.search_mag_icon);
+ mCollapsedIcon = (ImageView) findViewById(R.id.search_mag_icon);
// Set up icons and backgrounds.
mSearchPlate.setBackground(a.getDrawable(R.styleable.SearchView_queryBackground));
mSubmitArea.setBackground(a.getDrawable(R.styleable.SearchView_submitBackground));
- mSearchIconResId = a.getResourceId(R.styleable.SearchView_searchIcon, 0);
- mSearchButton.setImageResource(mSearchIconResId);
- mSubmitButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_goIcon));
+ mSearchButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_searchIcon));
+ mGoButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_goIcon));
mCloseButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_closeIcon));
mVoiceButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_voiceIcon));
- mSearchHintIcon.setImageDrawable(a.getDrawable(R.styleable.SearchView_searchIcon));
+ mCollapsedIcon.setImageDrawable(a.getDrawable(R.styleable.SearchView_searchIcon));
+
+ // Prior to L MR1, the search hint icon defaulted to searchIcon. If the
+ // style does not have an explicit value set, fall back to that.
+ if (a.hasValueOrEmpty(R.styleable.SearchView_searchHintIcon)) {
+ mSearchHintIcon = a.getDrawable(R.styleable.SearchView_searchHintIcon);
+ } else {
+ mSearchHintIcon = a.getDrawable(R.styleable.SearchView_searchIcon);
+ }
// Extract dropdown layout resource IDs for later use.
mSuggestionRowLayout = a.getResourceId(R.styleable.SearchView_suggestionRowLayout,
mSearchButton.setOnClickListener(mOnClickListener);
mCloseButton.setOnClickListener(mOnClickListener);
- mSubmitButton.setOnClickListener(mOnClickListener);
+ mGoButton.setOnClickListener(mOnClickListener);
mVoiceButton.setOnClickListener(mOnClickListener);
- mQueryTextView.setOnClickListener(mOnClickListener);
+ mSearchSrcTextView.setOnClickListener(mOnClickListener);
- mQueryTextView.addTextChangedListener(mTextWatcher);
- mQueryTextView.setOnEditorActionListener(mOnEditorActionListener);
- mQueryTextView.setOnItemClickListener(mOnItemClickListener);
- mQueryTextView.setOnItemSelectedListener(mOnItemSelectedListener);
- mQueryTextView.setOnKeyListener(mTextKeyListener);
+ mSearchSrcTextView.addTextChangedListener(mTextWatcher);
+ mSearchSrcTextView.setOnEditorActionListener(mOnEditorActionListener);
+ mSearchSrcTextView.setOnItemClickListener(mOnItemClickListener);
+ mSearchSrcTextView.setOnItemSelectedListener(mOnItemSelectedListener);
+ mSearchSrcTextView.setOnKeyListener(mTextKeyListener);
// Inform any listener of focus changes
- mQueryTextView.setOnFocusChangeListener(new OnFocusChangeListener() {
+ mSearchSrcTextView.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (mOnQueryTextFocusChangeListener != null) {
mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mDropDownAnchor = findViewById(mQueryTextView.getDropDownAnchor());
+ mDropDownAnchor = findViewById(mSearchSrcTextView.getDropDownAnchor());
if (mDropDownAnchor != null) {
mDropDownAnchor.addOnLayoutChangeListener(new OnLayoutChangeListener() {
@Override
if (mVoiceButtonEnabled) {
// Disable the microphone on the keyboard, as a mic is displayed near the text box
// TODO: use imeOptions to disable voice input when the new API will be available
- mQueryTextView.setPrivateImeOptions(IME_OPTION_NO_MICROPHONE);
+ mSearchSrcTextView.setPrivateImeOptions(IME_OPTION_NO_MICROPHONE);
}
updateViewsVisibility(isIconified());
}
* @attr ref android.R.styleable#SearchView_imeOptions
*/
public void setImeOptions(int imeOptions) {
- mQueryTextView.setImeOptions(imeOptions);
+ mSearchSrcTextView.setImeOptions(imeOptions);
}
/**
* @attr ref android.R.styleable#SearchView_imeOptions
*/
public int getImeOptions() {
- return mQueryTextView.getImeOptions();
+ return mSearchSrcTextView.getImeOptions();
}
/**
* @attr ref android.R.styleable#SearchView_inputType
*/
public void setInputType(int inputType) {
- mQueryTextView.setInputType(inputType);
+ mSearchSrcTextView.setInputType(inputType);
}
/**
* @attr ref android.R.styleable#SearchView_inputType
*/
public int getInputType() {
- return mQueryTextView.getInputType();
+ return mSearchSrcTextView.getInputType();
}
/** @hide */
if (!isFocusable()) return false;
// If it is not iconified, then give the focus to the text field
if (!isIconified()) {
- boolean result = mQueryTextView.requestFocus(direction, previouslyFocusedRect);
+ boolean result = mSearchSrcTextView.requestFocus(direction, previouslyFocusedRect);
if (result) {
updateViewsVisibility(false);
}
mClearingFocus = true;
setImeVisibility(false);
super.clearFocus();
- mQueryTextView.clearFocus();
+ mSearchSrcTextView.clearFocus();
mClearingFocus = false;
}
* @return the query string
*/
public CharSequence getQuery() {
- return mQueryTextView.getText();
+ return mSearchSrcTextView.getText();
}
/**
* text field.
*/
public void setQuery(CharSequence query, boolean submit) {
- mQueryTextView.setText(query);
+ mSearchSrcTextView.setText(query);
if (query != null) {
- mQueryTextView.setSelection(mQueryTextView.length());
+ mSearchSrcTextView.setSelection(mSearchSrcTextView.length());
mUserQuery = query;
}
public void setSuggestionsAdapter(CursorAdapter adapter) {
mSuggestionsAdapter = adapter;
- mQueryTextView.setAdapter(mSuggestionsAdapter);
+ mSearchSrcTextView.setAdapter(mSuggestionsAdapter);
}
/**
// Visibility of views that are visible when collapsed
final int visCollapsed = collapsed ? VISIBLE : GONE;
// Is there text in the query
- final boolean hasText = !TextUtils.isEmpty(mQueryTextView.getText());
+ final boolean hasText = !TextUtils.isEmpty(mSearchSrcTextView.getText());
mSearchButton.setVisibility(visCollapsed);
updateSubmitButton(hasText);
mSearchEditFrame.setVisibility(collapsed ? GONE : VISIBLE);
- mSearchHintIcon.setVisibility(mIconifiedByDefault ? GONE : VISIBLE);
+ mCollapsedIcon.setVisibility(mIconifiedByDefault ? GONE : VISIBLE);
updateCloseButton();
updateVoiceButton(!hasText);
updateSubmitArea();
&& (hasText || !mVoiceButtonEnabled)) {
visibility = VISIBLE;
}
- mSubmitButton.setVisibility(visibility);
+ mGoButton.setVisibility(visibility);
}
private void updateSubmitArea() {
int visibility = GONE;
if (isSubmitAreaEnabled()
- && (mSubmitButton.getVisibility() == VISIBLE
+ && (mGoButton.getVisibility() == VISIBLE
|| mVoiceButton.getVisibility() == VISIBLE)) {
visibility = VISIBLE;
}
}
private void updateCloseButton() {
- final boolean hasText = !TextUtils.isEmpty(mQueryTextView.getText());
+ final boolean hasText = !TextUtils.isEmpty(mSearchSrcTextView.getText());
// Should we show the close button? It is not shown if there's no focus,
// field is not iconified by default and there is no text in it.
final boolean showClose = hasText || (mIconifiedByDefault && !mExpandedInActionView);
mCloseButton.setVisibility(showClose ? VISIBLE : GONE);
- mCloseButton.getDrawable().setState(hasText ? ENABLED_STATE_SET : EMPTY_STATE_SET);
+ final Drawable closeButtonImg = mCloseButton.getDrawable();
+ if (closeButtonImg != null){
+ closeButtonImg.setState(hasText ? ENABLED_STATE_SET : EMPTY_STATE_SET);
+ }
}
private void postUpdateFocusedState() {
}
private void updateFocusedState() {
- boolean focused = mQueryTextView.hasFocus();
- mSearchPlate.getBackground().setState(focused ? FOCUSED_STATE_SET : EMPTY_STATE_SET);
- mSubmitArea.getBackground().setState(focused ? FOCUSED_STATE_SET : EMPTY_STATE_SET);
+ final boolean focused = mSearchSrcTextView.hasFocus();
+ final int[] stateSet = focused ? FOCUSED_STATE_SET : EMPTY_STATE_SET;
+ final Drawable searchPlateBg = mSearchPlate.getBackground();
+ if (searchPlateBg != null) {
+ searchPlateBg.setState(stateSet);
+ }
+ final Drawable submitAreaBg = mSubmitArea.getBackground();
+ if (submitAreaBg != null) {
+ submitAreaBg.setState(stateSet);
+ }
invalidate();
}
onSearchClicked();
} else if (v == mCloseButton) {
onCloseClicked();
- } else if (v == mSubmitButton) {
+ } else if (v == mGoButton) {
onSubmitQuery();
} else if (v == mVoiceButton) {
onVoiceClicked();
- } else if (v == mQueryTextView) {
+ } else if (v == mSearchSrcTextView) {
forceSuggestionQuery();
}
}
// entered query with the action key
SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode);
if ((actionKey != null) && (actionKey.getQueryActionMsg() != null)) {
- launchQuerySearch(keyCode, actionKey.getQueryActionMsg(), mQueryTextView.getText()
+ launchQuerySearch(keyCode, actionKey.getQueryActionMsg(), mSearchSrcTextView.getText()
.toString());
return true;
}
if (DBG) {
Log.d(LOG_TAG, "mTextListener.onKey(" + keyCode + "," + event + "), selection: "
- + mQueryTextView.getListSelection());
+ + mSearchSrcTextView.getListSelection());
}
// If a suggestion is selected, handle enter, search key, and action keys
// as presses on the selected suggestion
- if (mQueryTextView.isPopupShowing()
- && mQueryTextView.getListSelection() != ListView.INVALID_POSITION) {
+ if (mSearchSrcTextView.isPopupShowing()
+ && mSearchSrcTextView.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 (!mQueryTextView.isEmpty() && event.hasNoModifiers()) {
+ if (!mSearchSrcTextView.isEmpty() && event.hasNoModifiers()) {
if (event.getAction() == KeyEvent.ACTION_UP) {
if (keyCode == KeyEvent.KEYCODE_ENTER) {
v.cancelLongPress();
// Launch as a regular search.
- launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, mQueryTextView.getText()
+ launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, mSearchSrcTextView.getText()
.toString());
return true;
}
if (event.getAction() == KeyEvent.ACTION_DOWN) {
SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode);
if ((actionKey != null) && (actionKey.getQueryActionMsg() != null)) {
- launchQuerySearch(keyCode, actionKey.getQueryActionMsg(), mQueryTextView
+ launchQuerySearch(keyCode, actionKey.getQueryActionMsg(), mSearchSrcTextView
.getText().toString());
return true;
}
// "click")
if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH
|| keyCode == KeyEvent.KEYCODE_TAB) {
- int position = mQueryTextView.getListSelection();
+ int position = mSearchSrcTextView.getListSelection();
return onItemClicked(position, KeyEvent.KEYCODE_UNKNOWN, null);
}
// 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 : mQueryTextView
+ int selPoint = (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) ? 0 : mSearchSrcTextView
.length();
- mQueryTextView.setSelection(selPoint);
- mQueryTextView.setListSelection(0);
- mQueryTextView.clearListSelection();
- mQueryTextView.ensureImeVisible(true);
+ mSearchSrcTextView.setSelection(selPoint);
+ mSearchSrcTextView.setListSelection(0);
+ mSearchSrcTextView.clearListSelection();
+ mSearchSrcTextView.ensureImeVisible(true);
return true;
}
// Next, check for an "up and out" move
- if (keyCode == KeyEvent.KEYCODE_DPAD_UP && 0 == mQueryTextView.getListSelection()) {
+ if (keyCode == KeyEvent.KEYCODE_DPAD_UP && 0 == mSearchSrcTextView.getListSelection()) {
// TODO: restoreUserQuery();
// let ACTV complete the move
return false;
&& ((actionKey.getSuggestActionMsg() != null) || (actionKey
.getSuggestActionMsgColumn() != null))) {
// launch suggestion using action key column
- int position = mQueryTextView.getListSelection();
+ int position = mSearchSrcTextView.getListSelection();
if (position != ListView.INVALID_POSITION) {
Cursor c = mSuggestionsAdapter.getCursor();
if (c.moveToPosition(position)) {
}
private CharSequence getDecoratedHint(CharSequence hintText) {
- // If the field is always expanded, then don't add the search icon to the hint
- if (!mIconifiedByDefault) {
+ // If the field is always expanded or we don't have a search hint icon,
+ // then don't add the search icon to the hint.
+ if (!mIconifiedByDefault || mSearchHintIcon == null) {
return hintText;
}
- final Drawable searchIcon = getContext().getDrawable(mSearchIconResId);
- final int textSize = (int) (mQueryTextView.getTextSize() * 1.25);
- searchIcon.setBounds(0, 0, textSize, textSize);
+ final int textSize = (int) (mSearchSrcTextView.getTextSize() * 1.25);
+ mSearchHintIcon.setBounds(0, 0, textSize, textSize);
- final SpannableStringBuilder ssb = new SpannableStringBuilder(" "); // for the icon
+ final SpannableStringBuilder ssb = new SpannableStringBuilder(" ");
+ ssb.setSpan(new ImageSpan(mSearchHintIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.append(hintText);
- ssb.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return ssb;
}
private void updateQueryHint() {
if (mQueryHint != null) {
- mQueryTextView.setHint(getDecoratedHint(mQueryHint));
+ mSearchSrcTextView.setHint(getDecoratedHint(mQueryHint));
} else if (mSearchable != null) {
CharSequence hint = null;
int hintId = mSearchable.getHintId();
hint = getContext().getString(hintId);
}
if (hint != null) {
- mQueryTextView.setHint(getDecoratedHint(hint));
+ mSearchSrcTextView.setHint(getDecoratedHint(hint));
}
} else {
- mQueryTextView.setHint(getDecoratedHint(""));
+ mSearchSrcTextView.setHint(getDecoratedHint(""));
}
}
* Updates the auto-complete text view.
*/
private void updateSearchAutoComplete() {
- mQueryTextView.setDropDownAnimationStyle(0); // no animation
- mQueryTextView.setThreshold(mSearchable.getSuggestThreshold());
- mQueryTextView.setImeOptions(mSearchable.getImeOptions());
+ mSearchSrcTextView.setDropDownAnimationStyle(0); // no animation
+ mSearchSrcTextView.setThreshold(mSearchable.getSuggestThreshold());
+ mSearchSrcTextView.setImeOptions(mSearchable.getImeOptions());
int inputType = mSearchable.getInputType();
// We only touch this if the input type is set up for text (which it almost certainly
// should be, in the case of search!)
inputType |= InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
}
}
- mQueryTextView.setInputType(inputType);
+ mSearchSrcTextView.setInputType(inputType);
if (mSuggestionsAdapter != null) {
mSuggestionsAdapter.changeCursor(null);
}
if (mSearchable.getSuggestAuthority() != null) {
mSuggestionsAdapter = new SuggestionsAdapter(getContext(),
this, mSearchable, mOutsideDrawablesCache);
- mQueryTextView.setAdapter(mSuggestionsAdapter);
+ mSearchSrcTextView.setAdapter(mSuggestionsAdapter);
((SuggestionsAdapter) mSuggestionsAdapter).setQueryRefinement(
mQueryRefinement ? SuggestionsAdapter.REFINE_ALL
: SuggestionsAdapter.REFINE_BY_ENTRY);
int visibility = GONE;
if (mVoiceButtonEnabled && !isIconified() && empty) {
visibility = VISIBLE;
- mSubmitButton.setVisibility(GONE);
+ mGoButton.setVisibility(GONE);
}
mVoiceButton.setVisibility(visibility);
}
};
private void onTextChanged(CharSequence newText) {
- CharSequence text = mQueryTextView.getText();
+ CharSequence text = mSearchSrcTextView.getText();
mUserQuery = text;
boolean hasText = !TextUtils.isEmpty(text);
updateSubmitButton(hasText);
}
private void onSubmitQuery() {
- CharSequence query = mQueryTextView.getText();
+ CharSequence query = mSearchSrcTextView.getText();
if (query != null && TextUtils.getTrimmedLength(query) > 0) {
if (mOnQueryChangeListener == null
|| !mOnQueryChangeListener.onQueryTextSubmit(query.toString())) {
}
private void dismissSuggestions() {
- mQueryTextView.dismissDropDown();
+ mSearchSrcTextView.dismissDropDown();
}
private void onCloseClicked() {
- CharSequence text = mQueryTextView.getText();
+ CharSequence text = mSearchSrcTextView.getText();
if (TextUtils.isEmpty(text)) {
if (mIconifiedByDefault) {
// If the app doesn't override the close behavior
}
}
} else {
- mQueryTextView.setText("");
- mQueryTextView.requestFocus();
+ mSearchSrcTextView.setText("");
+ mSearchSrcTextView.requestFocus();
setImeVisibility(true);
}
private void onSearchClicked() {
updateViewsVisibility(false);
- mQueryTextView.requestFocus();
+ mSearchSrcTextView.requestFocus();
setImeVisibility(true);
if (mOnSearchClickListener != null) {
mOnSearchClickListener.onClick(this);
// Delayed update to make sure that the focus has settled down and window focus changes
// don't affect it. A synchronous update was not working.
postUpdateFocusedState();
- if (mQueryTextView.hasFocus()) {
+ if (mSearchSrcTextView.hasFocus()) {
forceSuggestionQuery();
}
}
setQuery("", false);
clearFocus();
updateViewsVisibility(true);
- mQueryTextView.setImeOptions(mCollapsedImeOptions);
+ mSearchSrcTextView.setImeOptions(mCollapsedImeOptions);
mExpandedInActionView = false;
}
if (mExpandedInActionView) return;
mExpandedInActionView = true;
- mCollapsedImeOptions = mQueryTextView.getImeOptions();
- mQueryTextView.setImeOptions(mCollapsedImeOptions | EditorInfo.IME_FLAG_NO_FULLSCREEN);
- mQueryTextView.setText("");
+ mCollapsedImeOptions = mSearchSrcTextView.getImeOptions();
+ mSearchSrcTextView.setImeOptions(mCollapsedImeOptions | EditorInfo.IME_FLAG_NO_FULLSCREEN);
+ mSearchSrcTextView.setText("");
setIconified(false);
}
? res.getDimensionPixelSize(R.dimen.dropdownitem_icon_width)
+ res.getDimensionPixelSize(R.dimen.dropdownitem_text_padding_left)
: 0;
- mQueryTextView.getDropDownBackground().getPadding(dropDownPadding);
+ mSearchSrcTextView.getDropDownBackground().getPadding(dropDownPadding);
int offset;
if (isLayoutRtl) {
offset = - dropDownPadding.left;
} else {
offset = anchorPadding - (dropDownPadding.left + iconOffset);
}
- mQueryTextView.setDropDownHorizontalOffset(offset);
+ mSearchSrcTextView.setDropDownHorizontalOffset(offset);
final int width = mDropDownAnchor.getWidth() + dropDownPadding.left
+ dropDownPadding.right + iconOffset - anchorPadding;
- mQueryTextView.setDropDownWidth(width);
+ mSearchSrcTextView.setDropDownWidth(width);
}
}
* Query rewriting.
*/
private void rewriteQueryFromSuggestion(int position) {
- CharSequence oldQuery = mQueryTextView.getText();
+ CharSequence oldQuery = mSearchSrcTextView.getText();
Cursor c = mSuggestionsAdapter.getCursor();
if (c == null) {
return;
* Sets the text in the query box, without updating the suggestions.
*/
private void setQuery(CharSequence query) {
- mQueryTextView.setText(query, true);
+ mSearchSrcTextView.setText(query, true);
// Move the cursor to the end
- mQueryTextView.setSelection(TextUtils.isEmpty(query) ? 0 : query.length());
+ mSearchSrcTextView.setSelection(TextUtils.isEmpty(query) ? 0 : query.length());
}
private void launchQuerySearch(int actionKey, String actionMsg, String query) {
}
private void forceSuggestionQuery() {
- mQueryTextView.doBeforeTextChanged();
- mQueryTextView.doAfterTextChanged();
+ mSearchSrcTextView.doBeforeTextChanged();
+ mSearchSrcTextView.doAfterTextChanged();
}
static boolean isLandscapeMode(Context context) {