1page.title=Searching within TV Apps
2page.tags=tv, leanback
3helpoutsWidget=true
4
5trainingnavtop=true
6
7@jd:body
8
9<div id="tb-wrapper">
10<div id="tb">
11  <h2>This lesson teaches you to</h2>
12  <ol>
13    <li><a href="#add-search-action">Add a Search Action</a></li>
14    <li><a href="#add-search-ui">Add Search Input and Results</a></li>
15  </ol>
16
17</div>
18</div>
19
20
21<p>
22  Users frequently have specific content in mind when using a media app on TV. If your app contains
23  a large catalog of content, browsing for a specific title may not be the most efficient way for
24  users to find what they are looking for. A search interface can help your users get to the
25  content they want faster than browsing.
26</p>
27
28<p>
29  The <a href="{@docRoot}tools/support-library/features.html#v17-leanback">Leanback support
30  library</a> provides a set of classes to enable a standard search interface within your app that
31  is consistent with other search functions on TV and provides features such as voice input.
32</p>
33
34<p>
35  This lesson discusses how to provide a search interface in your app using Leanback support
36  library classes.
37</p>
38
39
40<h2 id="add-search-action">Add a Search Action</h2>
41
42<p>
43  When you use the {@link android.support.v17.leanback.app.BrowseFragment} class for a media
44  browsing interface, you can enable a search interface as a standard part of the user
45  interface. The search interface is an icon that appears in the layout when you set {@link
46  android.view.View.OnClickListener} on the {@link android.support.v17.leanback.app.BrowseFragment}
47  object. The following sample code demonstrates this technique.
48</p>
49
50<pre>
51&#64;Override
52public void onCreate(Bundle savedInstanceState) {
53    super.onCreate(savedInstanceState);
54    setContentView(R.layout.browse_activity);
55
56    mBrowseFragment = (BrowseFragment)
57            getFragmentManager().findFragmentById(R.id.browse_fragment);
58
59    ...
60
61    mBrowseFragment.setOnSearchClickedListener(new View.OnClickListener() {
62        &#64;Override
63        public void onClick(View view) {
64            Intent intent = new Intent(BrowseActivity.this, SearchActivity.class);
65            startActivity(intent);
66        }
67    });
68
69    mBrowseFragment.setAdapter(buildAdapter());
70}
71</pre>
72
73<p class="note">
74  <strong>Note:</strong> You can set the color of the search icon using the
75  {@link android.support.v17.leanback.app.BrowseFragment#setSearchAffordanceColor}.
76</p>
77
78
79<h2 id="add-search-ui">Add a Search Input and Results</h2>
80
81<p>
82  When a user selects the search icon, the system invokes a search activity via the defined intent.
83  Your search activity should use a linear layout containing a {@link
84  android.support.v17.leanback.app.SearchFragment}. This fragment must also implement the {@link
85  android.support.v17.leanback.app.SearchFragment.SearchResultProvider} interface in order to
86  display the results of a search.
87</p>
88
89<p>
90  The following code sample shows how to extend the {@link
91  android.support.v17.leanback.app.SearchFragment} class to provide a search interface and results:
92</p>
93
94<pre>
95public class MySearchFragment extends SearchFragment
96        implements SearchFragment.SearchResultProvider {
97
98    private static final int SEARCH_DELAY_MS = 300;
99    private ArrayObjectAdapter mRowsAdapter;
100    private Handler mHandler = new Handler();
101    private SearchRunnable mDelayedLoad;
102
103    &#64;Override
104    public void onCreate(Bundle savedInstanceState) {
105        super.onCreate(savedInstanceState);
106
107        mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
108        setSearchResultProvider(this);
109        setOnItemClickedListener(getDefaultItemClickedListener());
110        mDelayedLoad = new SearchRunnable();
111    }
112
113    &#64;Override
114    public ObjectAdapter getResultsAdapter() {
115        return mRowsAdapter;
116    }
117
118    &#64;Override
119    public boolean onQueryTextChange(String newQuery) {
120        mRowsAdapter.clear();
121        if (!TextUtils.isEmpty(newQuery)) {
122            mDelayedLoad.setSearchQuery(newQuery);
123            mHandler.removeCallbacks(mDelayedLoad);
124            mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS);
125        }
126        return true;
127    }
128
129    &#64;Override
130    public boolean onQueryTextSubmit(String query) {
131        mRowsAdapter.clear();
132        if (!TextUtils.isEmpty(query)) {
133            mDelayedLoad.setSearchQuery(query);
134            mHandler.removeCallbacks(mDelayedLoad);
135            mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS);
136        }
137        return true;
138    }
139}
140</pre>
141
142<p>
143  The example code shown above is meant to be used with a separate {@code SearchRunnable} class
144  that runs the search query on a separate thread. This technique keeps potentially slow-running
145  queries from blocking the main user interface thread.
146</p>
147