FileDocCategorySizeDatePackage
SearchBar.javaAPI DocAndroid 5.1 API27780Thu Mar 12 22:22:56 GMT 2015android.support.v17.leanback.widget

SearchBar

public class SearchBar extends android.widget.RelativeLayout

SearchBar is a search widget.

Note: Your application will need to request android.permission.RECORD_AUDIO

Fields Summary
private static final String
TAG
private static final boolean
DEBUG
private static final float
FULL_LEFT_VOLUME
private static final float
FULL_RIGHT_VOLUME
private static final int
DEFAULT_PRIORITY
private static final int
DO_NOT_LOOP
private static final float
DEFAULT_RATE
private AudioManager.OnAudioFocusChangeListener
mAudioFocusChangeListener
private SearchBarListener
mSearchBarListener
private SearchEditText
mSearchTextEditor
private SpeechOrbView
mSpeechOrbView
private android.widget.ImageView
mBadgeView
private String
mSearchQuery
private String
mHint
private String
mTitle
private android.graphics.drawable.Drawable
mBadgeDrawable
private final android.os.Handler
mHandler
private final android.view.inputmethod.InputMethodManager
mInputMethodManager
private boolean
mAutoStartRecognition
private android.graphics.drawable.Drawable
mBarBackground
private final int
mTextColor
private final int
mTextColorSpeechMode
private final int
mTextHintColor
private final int
mTextHintColorSpeechMode
private int
mBackgroundAlpha
private int
mBackgroundSpeechAlpha
private int
mBarHeight
private android.speech.SpeechRecognizer
mSpeechRecognizer
private SpeechRecognitionCallback
mSpeechRecognitionCallback
private boolean
mListening
private android.media.SoundPool
mSoundPool
private android.util.SparseIntArray
mSoundMap
private boolean
mRecognizing
private final android.content.Context
mContext
private android.media.AudioManager
mAudioManager
Constructors Summary
public SearchBar(android.content.Context context)


       
        this(context, null);
    
public SearchBar(android.content.Context context, android.util.AttributeSet attrs)

        this(context, attrs, 0);
    
public SearchBar(android.content.Context context, android.util.AttributeSet attrs, int defStyle)

        super(context, attrs, defStyle);
        mContext = context;

        Resources r = getResources();

        LayoutInflater inflater = LayoutInflater.from(getContext());
        inflater.inflate(R.layout.lb_search_bar, this, true);

        mBarHeight = getResources().getDimensionPixelSize(R.dimen.lb_search_bar_height);
        RelativeLayout.LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                mBarHeight);
        params.addRule(ALIGN_PARENT_TOP, RelativeLayout.TRUE);
        setLayoutParams(params);
        setBackgroundColor(Color.TRANSPARENT);
        setClipChildren(false);

        mSearchQuery = "";
        mInputMethodManager =
                (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE);

        mTextColorSpeechMode = r.getColor(R.color.lb_search_bar_text_speech_mode);
        mTextColor = r.getColor(R.color.lb_search_bar_text);

        mBackgroundSpeechAlpha = r.getInteger(R.integer.lb_search_bar_speech_mode_background_alpha);
        mBackgroundAlpha = r.getInteger(R.integer.lb_search_bar_text_mode_background_alpha);

        mTextHintColorSpeechMode = r.getColor(R.color.lb_search_bar_hint_speech_mode);
        mTextHintColor = r.getColor(R.color.lb_search_bar_hint);

        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
    
Methods Summary
public voiddisplayCompletions(java.util.List completions)
Update the completion list shown by the IME

param
completions list of completions shown in the IME, can be null or empty to clear them

        List<CompletionInfo> infos = new ArrayList<CompletionInfo>();
        if (null != completions) {
            for (String completion : completions) {
                infos.add(new CompletionInfo(infos.size(), infos.size(), completion));
            }
        }

        mInputMethodManager.displayCompletions(mSearchTextEditor,
                infos.toArray(new CompletionInfo[] {}));
    
private voidenforceAudioRecordPermission()

        String permission = "android.permission.RECORD_AUDIO";
        int res = getContext().checkCallingOrSelfPermission(permission);
        if (PackageManager.PERMISSION_GRANTED != res) {
            throw new IllegalStateException("android.permission.RECORD_AUDIO required for search");
        }
    
public android.graphics.drawable.DrawablegetBadgeDrawable()
Returns the badge drawable

        return mBadgeDrawable;
    
public java.lang.CharSequencegetHint()
Returns the current search bar hint text.

        return mHint;
    
public java.lang.StringgetTitle()
Returns the current title

        return mTitle;
    
private voidhideNativeKeyboard()

        mInputMethodManager.hideSoftInputFromWindow(mSearchTextEditor.getWindowToken(),
                InputMethodManager.RESULT_UNCHANGED_SHOWN);
    
private booleanisVoiceMode()

        return mSpeechOrbView.isFocused();
    
private voidloadSounds(android.content.Context context)

        int[] sounds = {
                R.raw.lb_voice_failure,
                R.raw.lb_voice_open,
                R.raw.lb_voice_no_input,
                R.raw.lb_voice_success,
        };
        for (int sound : sounds) {
            mSoundMap.put(sound, mSoundPool.load(context, sound, 1));
        }
    
protected voidonAttachedToWindow()

        super.onAttachedToWindow();
        if (DEBUG) Log.v(TAG, "Loading soundPool");
        mSoundPool = new SoundPool(2, AudioManager.STREAM_SYSTEM, 0);
        loadSounds(mContext);
    
protected voidonDetachedFromWindow()

        if (DEBUG) Log.v(TAG, "Releasing SoundPool");
        mSoundPool.release();
        super.onDetachedFromWindow();
    
protected voidonFinishInflate()

        super.onFinishInflate();

        RelativeLayout items = (RelativeLayout)findViewById(R.id.lb_search_bar_items);
        mBarBackground = items.getBackground();

        mSearchTextEditor = (SearchEditText)findViewById(R.id.lb_search_text_editor);
        mBadgeView = (ImageView)findViewById(R.id.lb_search_bar_badge);
        if (null != mBadgeDrawable) {
            mBadgeView.setImageDrawable(mBadgeDrawable);
        }

        mSearchTextEditor.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View view, boolean hasFocus) {
                if (DEBUG) Log.v(TAG, "EditText.onFocusChange " + hasFocus);
                if (hasFocus) {
                    showNativeKeyboard();
                }
                updateUi(hasFocus);
            }
        });
        final Runnable mOnTextChangedRunnable = new Runnable() {
            @Override
            public void run() {
                setSearchQueryInternal(mSearchTextEditor.getText().toString());
            }
        };
        mSearchTextEditor.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
                // don't propagate event during speech recognition.
                if (mRecognizing) {
                    return;
                }
                // while IME opens,  text editor becomes "" then restores to current value
                mHandler.removeCallbacks(mOnTextChangedRunnable);
                mHandler.post(mOnTextChangedRunnable);
            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        });
        mSearchTextEditor.setOnKeyboardDismissListener(
                new SearchEditText.OnKeyboardDismissListener() {
                    @Override
                    public void onKeyboardDismiss() {
                        if (null != mSearchBarListener) {
                            mSearchBarListener.onKeyboardDismiss(mSearchQuery);
                        }
                    }
                });

        mSearchTextEditor.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView textView, int action, KeyEvent keyEvent) {
                if (DEBUG) Log.v(TAG, "onEditorAction: " + action + " event: " + keyEvent);
                boolean handled = true;
                if ((EditorInfo.IME_ACTION_SEARCH == action ||
                        EditorInfo.IME_NULL == action) && null != mSearchBarListener) {
                    if (DEBUG) Log.v(TAG, "Action or enter pressed");
                    hideNativeKeyboard();
                    mHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (DEBUG) Log.v(TAG, "Delayed action handling (search)");
                            submitQuery();
                        }
                    }, 500);

                } else if (EditorInfo.IME_ACTION_NONE == action && null != mSearchBarListener) {
                    if (DEBUG) Log.v(TAG, "Escaped North");
                    hideNativeKeyboard();
                    mHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (DEBUG) Log.v(TAG, "Delayed action handling (escape_north)");
                            mSearchBarListener.onKeyboardDismiss(mSearchQuery);
                        }
                    }, 500);
                } else if (EditorInfo.IME_ACTION_GO == action) {
                    if (DEBUG) Log.v(TAG, "Voice Clicked");
                        hideNativeKeyboard();
                        mHandler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                if (DEBUG) Log.v(TAG, "Delayed action handling (voice_mode)");
                                mAutoStartRecognition = true;
                                mSpeechOrbView.requestFocus();
                            }
                        }, 500);
                } else {
                    handled = false;
                }

                return handled;
            }
        });

        mSearchTextEditor.setPrivateImeOptions("EscapeNorth=1;VoiceDismiss=1;");

        mSpeechOrbView = (SpeechOrbView)findViewById(R.id.lb_search_bar_speech_orb);
        mSpeechOrbView.setOnOrbClickedListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                toggleRecognition();
            }
        });
        mSpeechOrbView.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View view, boolean hasFocus) {
                if (DEBUG) Log.v(TAG, "SpeechOrb.onFocusChange " + hasFocus);
                if (hasFocus) {
                    hideNativeKeyboard();
                    if (mAutoStartRecognition) {
                        startRecognition();
                        mAutoStartRecognition = false;
                    }
                } else {
                    stopRecognition();
                }
                updateUi(hasFocus);
            }
        });

        updateUi(hasFocus());
        updateHint();
    
private voidplay(int resId)

        mHandler.post(new Runnable() {
            @Override
            public void run() {
                int sound = mSoundMap.get(resId);
                mSoundPool.play(sound, FULL_LEFT_VOLUME, FULL_RIGHT_VOLUME, DEFAULT_PRIORITY,
                        DO_NOT_LOOP, DEFAULT_RATE);
            }
        });
    
private voidplaySearchFailure()

        play(R.raw.lb_voice_failure);
    
private voidplaySearchNoInput()

        play(R.raw.lb_voice_no_input);
    
private voidplaySearchOpen()

        play(R.raw.lb_voice_open);
    
private voidplaySearchSuccess()

        play(R.raw.lb_voice_success);
    
public voidsetBadgeDrawable(android.graphics.drawable.Drawable drawable)
Set the badge drawable showing inside the search bar.

param
drawable The drawable to be used in the search bar.

        mBadgeDrawable = drawable;
        if (null != mBadgeView) {
            mBadgeView.setImageDrawable(drawable);
            if (null != drawable) {
                mBadgeView.setVisibility(View.VISIBLE);
            } else {
                mBadgeView.setVisibility(View.GONE);
            }
        }
    
public voidsetNextFocusDownId(int viewId)

        mSpeechOrbView.setNextFocusDownId(viewId);
        mSearchTextEditor.setNextFocusDownId(viewId);
    
public voidsetSearchBarListener(android.support.v17.leanback.widget.SearchBar$SearchBarListener listener)
Set a listener for when the term search changes

param
listener

        mSearchBarListener = listener;
    
public voidsetSearchQuery(java.lang.String query)
Set the search query

param
query the search query to use

        stopRecognition();
        mSearchTextEditor.setText(query);
        setSearchQueryInternal(query);
    
private voidsetSearchQueryInternal(java.lang.String query)

        if (DEBUG) Log.v(TAG, "setSearchQueryInternal " + query);
        if (TextUtils.equals(mSearchQuery, query)) {
            return;
        }
        mSearchQuery = query;

        if (null != mSearchBarListener) {
            mSearchBarListener.onSearchQueryChange(mSearchQuery);
        }
    
public voidsetSpeechRecognitionCallback(SpeechRecognitionCallback request)

        mSpeechRecognitionCallback = request;
        if (mSpeechRecognitionCallback != null && mSpeechRecognizer != null) {
            throw new IllegalStateException("Can't have speech recognizer and request");
        }
    
public voidsetSpeechRecognizer(android.speech.SpeechRecognizer recognizer)
Set the speech recognizer to be used when doing voice search. The Activity/Fragment is in charge of creating and destroying the recognizer with its own lifecycle.

param
recognizer a SpeechRecognizer

        if (null != mSpeechRecognizer) {
            mSpeechRecognizer.setRecognitionListener(null);
            if (mListening) {
                mSpeechRecognizer.cancel();
                mListening = false;
            }
        }
        mSpeechRecognizer = recognizer;
        if (mSpeechRecognizer != null) {
            enforceAudioRecordPermission();
        }
        if (mSpeechRecognitionCallback != null && mSpeechRecognizer != null) {
            throw new IllegalStateException("Can't have speech recognizer and request");
        }
    
public voidsetTitle(java.lang.String title)
Set the title text used in the hint shown in the search bar.

param
title The hint to use.

        mTitle = title;
        updateHint();
    
private voidshowNativeKeyboard()

        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mSearchTextEditor.requestFocusFromTouch();
                mSearchTextEditor.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),
                        SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN,
                        mSearchTextEditor.getWidth(), mSearchTextEditor.getHeight(), 0));
                mSearchTextEditor.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),
                        SystemClock.uptimeMillis(), MotionEvent.ACTION_UP,
                        mSearchTextEditor.getWidth(), mSearchTextEditor.getHeight(), 0));
            }
        });
    
public voidstartRecognition()
Start the voice recognition

        if (DEBUG) Log.v(TAG, String.format("startRecognition (listening: %s, recognizing: %s)",
                mListening, mRecognizing));

        if (mRecognizing) return;
        mRecognizing = true;
        if (!hasFocus()) {
            requestFocus();
        }
        if (mSpeechRecognitionCallback != null) {
            mSearchTextEditor.setText("");
            mSearchTextEditor.setHint("");
            mSpeechRecognitionCallback.recognizeSpeech();
            return;
        }
        if (null == mSpeechRecognizer) return;

        // Request audio focus
        int result = mAudioManager.requestAudioFocus(mAudioFocusChangeListener,
                // Use the music stream.
                AudioManager.STREAM_MUSIC,
                // Request exclusive transient focus.
                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);


        if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
            Log.w(TAG, "Could not get audio focus");
        }

        mSearchTextEditor.setText("");

        Intent recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);

        recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
                RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
        recognizerIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);

        mSpeechRecognizer.setRecognitionListener(new RecognitionListener() {
            @Override
            public void onReadyForSpeech(Bundle bundle) {
                if (DEBUG) Log.v(TAG, "onReadyForSpeech");
                mSpeechOrbView.showListening();
                playSearchOpen();
            }

            @Override
            public void onBeginningOfSpeech() {
                if (DEBUG) Log.v(TAG, "onBeginningOfSpeech");
            }

            @Override
            public void onRmsChanged(float rmsdB) {
                if (DEBUG) Log.v(TAG, "onRmsChanged " + rmsdB);
                int level = rmsdB < 0 ? 0 : (int)(10 * rmsdB);
                mSpeechOrbView.setSoundLevel(level);
            }

            @Override
            public void onBufferReceived(byte[] bytes) {
                if (DEBUG) Log.v(TAG, "onBufferReceived " + bytes.length);
            }

            @Override
            public void onEndOfSpeech() {
                if (DEBUG) Log.v(TAG, "onEndOfSpeech");
            }

            @Override
            public void onError(int error) {
                if (DEBUG) Log.v(TAG, "onError " + error);
                switch (error) {
                    case SpeechRecognizer.ERROR_NETWORK_TIMEOUT:
                        Log.w(TAG, "recognizer network timeout");
                        break;
                    case SpeechRecognizer.ERROR_NETWORK:
                        Log.w(TAG, "recognizer network error");
                        break;
                    case SpeechRecognizer.ERROR_AUDIO:
                        Log.w(TAG, "recognizer audio error");
                        break;
                    case SpeechRecognizer.ERROR_SERVER:
                        Log.w(TAG, "recognizer server error");
                        break;
                    case SpeechRecognizer.ERROR_CLIENT:
                        Log.w(TAG, "recognizer client error");
                        break;
                    case SpeechRecognizer.ERROR_SPEECH_TIMEOUT:
                        Log.w(TAG, "recognizer speech timeout");
                        break;
                    case SpeechRecognizer.ERROR_NO_MATCH:
                        Log.w(TAG, "recognizer no match");
                        break;
                    case SpeechRecognizer.ERROR_RECOGNIZER_BUSY:
                        Log.w(TAG, "recognizer busy");
                        break;
                    case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS:
                        Log.w(TAG, "recognizer insufficient permissions");
                        break;
                    default:
                        Log.d(TAG, "recognizer other error");
                        break;
                }

                stopRecognition();
                playSearchFailure();
            }

            @Override
            public void onResults(Bundle bundle) {
                if (DEBUG) Log.v(TAG, "onResults");
                final ArrayList<String> matches =
                        bundle.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
                if (matches != null) {
                    if (DEBUG) Log.v(TAG, "Got results" + matches);

                    mSearchQuery = matches.get(0);
                    mSearchTextEditor.setText(mSearchQuery);
                    submitQuery();
                }

                stopRecognition();
                playSearchSuccess();
            }

            @Override
            public void onPartialResults(Bundle bundle) {
                ArrayList<String> results = bundle.getStringArrayList(
                        SpeechRecognizer.RESULTS_RECOGNITION);
                if (DEBUG) Log.v(TAG, "onPartialResults " + bundle + " results " +
                        (results == null ? results : results.size()));
                if (results == null || results.size() == 0) {
                    return;
                }

                // stableText: high confidence text from PartialResults, if any.
                // Otherwise, existing stable text.
                final String stableText = results.get(0);
                if (DEBUG) Log.v(TAG, "onPartialResults stableText " + stableText);

                // pendingText: low confidence text from PartialResults, if any.
                // Otherwise, empty string.
                final String pendingText = results.size() > 1 ? results.get(1) : null;
                if (DEBUG) Log.v(TAG, "onPartialResults pendingText " + pendingText);

                mSearchTextEditor.updateRecognizedText(stableText, pendingText);
            }

            @Override
            public void onEvent(int i, Bundle bundle) {

            }
        });

        mListening = true;
        mSpeechRecognizer.startListening(recognizerIntent);
    
public voidstopRecognition()
Stop the recognition if already started

        if (DEBUG) Log.v(TAG, String.format("stopRecognition (listening: %s, recognizing: %s)",
                mListening, mRecognizing));

        if (!mRecognizing) return;

        // Edit text content was cleared when starting recogition; ensure the content is restored
        // in error cases
        mSearchTextEditor.setText(mSearchQuery);
        mSearchTextEditor.setHint(mHint);

        mRecognizing = false;

        if (mSpeechRecognitionCallback != null || null == mSpeechRecognizer) return;

        mSpeechOrbView.showNotListening();

        if (mListening) {
            mSpeechRecognizer.cancel();
            mListening = false;
            mAudioManager.abandonAudioFocus(mAudioFocusChangeListener);
        }

        mSpeechRecognizer.setRecognitionListener(null);
    
private voidsubmitQuery()

        if (!TextUtils.isEmpty(mSearchQuery) && null != mSearchBarListener) {
            mSearchBarListener.onSearchQuerySubmit(mSearchQuery);
        }
    
private voidtoggleRecognition()

        if (mRecognizing) {
            stopRecognition();
        } else {
            startRecognition();
        }
    
private voidupdateHint()
This will update the hint for the search bar properly depending on state and provided title

        String title = getResources().getString(R.string.lb_search_bar_hint);
        if (!TextUtils.isEmpty(mTitle)) {
            if (isVoiceMode()) {
                title = getResources().getString(R.string.lb_search_bar_hint_with_title_speech, mTitle);
            } else {
                title = getResources().getString(R.string.lb_search_bar_hint_with_title, mTitle);
            }
        } else if (isVoiceMode()) {
            title = getResources().getString(R.string.lb_search_bar_hint_speech);
        }
        mHint = title;
        if (mSearchTextEditor != null) {
            mSearchTextEditor.setHint(mHint);
        }
    
private voidupdateUi(boolean hasFocus)

        if (hasFocus) {
            mBarBackground.setAlpha(mBackgroundSpeechAlpha);
            if (isVoiceMode()) {
                mSearchTextEditor.setTextColor(mTextHintColorSpeechMode);
                mSearchTextEditor.setHintTextColor(mTextHintColorSpeechMode);
            } else {
                mSearchTextEditor.setTextColor(mTextColorSpeechMode);
                mSearchTextEditor.setHintTextColor(mTextHintColorSpeechMode);
            }
        } else {
            mBarBackground.setAlpha(mBackgroundAlpha);
            mSearchTextEditor.setTextColor(mTextColor);
            mSearchTextEditor.setHintTextColor(mTextHintColor);
        }

        updateHint();