SearchBar.java revision 514bdd5473ae7f4da990d6035422d0784c6c344e
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14package android.support.v17.leanback.widget;
15
16import android.content.Context;
17import android.graphics.drawable.Drawable;
18import android.os.Handler;
19import android.os.SystemClock;
20import android.text.Editable;
21import android.text.TextUtils;
22import android.text.TextWatcher;
23import android.util.AttributeSet;
24import android.util.Log;
25import android.view.inputmethod.EditorInfo;
26import android.view.KeyEvent;
27import android.view.MotionEvent;
28import android.view.View;
29import android.widget.ImageView;
30import android.widget.RelativeLayout;
31import android.support.v17.leanback.R;
32import android.widget.TextView;
33
34/**
35 * SearchBar is a search widget.
36 */
37public class SearchBar extends RelativeLayout {
38    private static final String TAG = SearchBar.class.getSimpleName();
39    private static final boolean DEBUG = false;
40
41    /**
42     * Listener for search query changes
43     */
44    public interface SearchBarListener {
45
46        /**
47         * Method invoked when the search bar detects a change in the query.
48         *
49         * @param query The current full query.
50         */
51        public void onSearchQueryChange(String query);
52
53        /**
54         * Method invoked when the search query is submitted.
55         *
56         * @param query The query being submitted.
57         */
58        public void onSearchQuerySubmit(String query);
59
60        /**
61         * Method invoked when the IME is being dismissed.
62         *
63         * @param query The query set in the search bar at the time the IME is being dismissed.
64         */
65        public void onKeyboardDismiss(String query);
66    }
67
68    private SearchBarListener mSearchBarListener;
69    private SearchEditText mSearchTextEditor;
70    private ImageView mBadgeView;
71    private String mSearchQuery;
72    private String mTitle;
73    private Drawable mBadgeDrawable;
74    private final Handler mHandler = new Handler();
75
76    public SearchBar(Context context) {
77        this(context, null);
78    }
79
80    public SearchBar(Context context, AttributeSet attrs) {
81        this(context, attrs, 0);
82    }
83
84    public SearchBar(Context context, AttributeSet attrs, int defStyle) {
85        super(context, attrs, defStyle);
86        mSearchQuery = "";
87    }
88
89    @Override
90    protected void onFinishInflate() {
91        super.onFinishInflate();
92
93        mSearchTextEditor = (SearchEditText)findViewById(R.id.lb_search_text_editor);
94        mBadgeView = (ImageView)findViewById(R.id.lb_search_bar_badge);
95        if (null != mBadgeDrawable) {
96            mBadgeView.setImageDrawable(mBadgeDrawable);
97        }
98
99        mSearchTextEditor.setOnFocusChangeListener(new OnFocusChangeListener() {
100            @Override
101            public void onFocusChange(View view, boolean hasFocus) {
102                if (DEBUG) Log.v(TAG, "onFocusChange " + hasFocus);
103                if (hasFocus) {
104                    showNativeKeyboard();
105                }
106            }
107        });
108        mSearchTextEditor.addTextChangedListener(new TextWatcher() {
109            @Override
110            public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
111
112            }
113
114            @Override
115            public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
116                setSearchQuery(charSequence.toString());
117            }
118
119            @Override
120            public void afterTextChanged(Editable editable) {
121
122            }
123        });
124        mSearchTextEditor.setOnKeyboardDismissListener(
125                new SearchEditText.OnKeyboardDismissListener() {
126                    @Override
127                    public void onKeyboardDismiss() {
128                        if (null != mSearchBarListener) {
129                            mSearchBarListener.onKeyboardDismiss(mSearchQuery);
130                        }
131                    }
132                });
133        mSearchTextEditor.setOnEditorActionListener(new TextView.OnEditorActionListener() {
134            @Override
135            public boolean onEditorAction(TextView textView, int action, KeyEvent keyEvent) {
136                if (EditorInfo.IME_ACTION_SEARCH == action && null != mSearchBarListener) {
137                    mSearchBarListener.onSearchQuerySubmit(mSearchQuery);
138                    return true;
139                }
140                return false;
141            }
142        });
143
144        updateHint();
145    }
146
147    @Override
148    protected void onAttachedToWindow() {
149        super.onAttachedToWindow();
150        mHandler.post(new Runnable() {
151            @Override
152            public void run() {
153                mSearchTextEditor.requestFocus();
154                mSearchTextEditor.requestFocusFromTouch();
155            }
156        });
157    }
158
159    /**
160     * Set a listener for when the term search changes
161     * @param listener
162     */
163    public void setSearchBarListener(SearchBarListener listener) {
164        mSearchBarListener = listener;
165    }
166
167    /**
168     * Set the search query
169     * @param query the search query to use
170     */
171    public void setSearchQuery(String query) {
172        if (query.equals(mSearchQuery)) {
173            return;
174        }
175        mSearchQuery = query;
176        if (null != mSearchBarListener) {
177            mSearchBarListener.onSearchQueryChange(mSearchQuery);
178        }
179    }
180
181    /**
182     * Set the title text used in the hint shown in the search bar.
183     * @param title The hint to use.
184     */
185    public void setTitle(String title) {
186        mTitle = title;
187        updateHint();
188    }
189
190    /**
191     * Returns the current title
192     */
193    public String getTitle() {
194        return mTitle;
195    }
196
197    /**
198     * Set the badge drawable showing inside the search bar.
199     * @param drawable The drawable to be used in the search bar.
200     */
201    public void setBadgeDrawable(Drawable drawable) {
202        mBadgeDrawable = drawable;
203        if (null != mBadgeView) {
204            mBadgeView.setImageDrawable(drawable);
205            if (null != drawable) {
206                mBadgeView.setVisibility(View.VISIBLE);
207            } else {
208                mBadgeView.setVisibility(View.GONE);
209            }
210        }
211    }
212
213    /**
214     * Returns the badge drawable
215     */
216    public Drawable getBadgeDrawable() {
217        return mBadgeDrawable;
218    }
219
220    protected void showNativeKeyboard() {
221        mHandler.post(new Runnable() {
222            @Override
223            public void run() {
224                mSearchTextEditor.requestFocusFromTouch();
225                mSearchTextEditor.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),
226                        SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN,
227                        mSearchTextEditor.getWidth(), mSearchTextEditor.getHeight(), 0));
228                mSearchTextEditor.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),
229                        SystemClock.uptimeMillis(), MotionEvent.ACTION_UP,
230                        mSearchTextEditor.getWidth(), mSearchTextEditor.getHeight(), 0));
231            }
232        });
233    }
234
235    /**
236     * This will update the hint for the search bar properly depending on state and provided title
237     */
238    protected void updateHint() {
239        if (null == mSearchTextEditor) return;
240
241        String title = getResources().getString(R.string.lb_search_bar_hint);
242        if (!TextUtils.isEmpty(mTitle)) {
243            title = getResources().getString(R.string.lb_search_bar_hint_with_title, mTitle);
244        }
245        mSearchTextEditor.setHint(title);
246    }
247
248}
249