SearchFragment.java revision 17993c442c26161f684d6c0c6867a746f3148548
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.app;
15
16import android.app.Fragment;
17import android.os.Bundle;
18import android.os.Handler;
19import android.support.v17.leanback.widget.ObjectAdapter;
20import android.support.v17.leanback.widget.OnItemClickedListener;
21import android.support.v17.leanback.widget.OnItemSelectedListener;
22import android.support.v17.leanback.widget.SearchBar;
23import android.view.LayoutInflater;
24import android.view.View;
25import android.view.ViewGroup;
26import android.widget.FrameLayout;
27import android.widget.RelativeLayout;
28import android.support.v17.leanback.R;
29
30/**
31 * A fragment to handle searches
32 */
33public class SearchFragment extends Fragment {
34    private static final String TAG = SearchFragment.class.getSimpleName();
35    private static final String ARG_QUERY = SearchFragment.class.getCanonicalName() + ".query";
36
37    /**
38     * Search API exposed to application
39     */
40    public static interface SearchResultProvider {
41        /**
42         * When using the SearchFragment, this is the entry point for the application
43         * to receive the search query and provide the corresponding results.
44         *
45         * The returned ObjectAdapter can be populated asynchronously.
46         *
47         * As results are retrieved, the application should use the data set notification methods
48         * on the ObjectAdapter to instruct the SearchFragment to update the results.
49         *
50         * @param searchQuery The search query entered by the user.
51         * @return An ObjectAdapter containing the structured results for the provided search query.
52         */
53        public ObjectAdapter results(String searchQuery);
54    }
55
56    private final RowsFragment mRowsFragment = new RowsFragment();
57    private final Handler mHandler = new Handler();
58
59    private RelativeLayout mSearchFrame;
60    private SearchBar mSearchBar;
61    private FrameLayout mResultsFrame;
62    private SearchResultProvider mProvider;
63    private String mPendingQuery = null;
64
65    /**
66     * @param args Bundle to use for the arguments, if null a new Bundle will be created.
67     */
68    public static Bundle createArgs(Bundle args, String query) {
69        if (args == null) {
70            args = new Bundle();
71        }
72        args.putString(ARG_QUERY, query);
73        return args;
74    }
75
76    /**
77     * Create a search fragment with a given search query to start with
78     *
79     * You should only use this if you need to start the search fragment with a pre-filled query
80     *
81     * @param query the search query to start with
82     * @return a new SearchFragment
83     */
84    public static SearchFragment newInstance(String query) {
85        SearchFragment fragment = new SearchFragment();
86        Bundle args = createArgs(null, query);
87        fragment.setArguments(args);
88        return fragment;
89    }
90
91    @Override
92    public void onCreate(Bundle savedInstanceState) {
93        super.onCreate(savedInstanceState);
94    }
95
96    @Override
97    public View onCreateView(LayoutInflater inflater, ViewGroup container,
98                             Bundle savedInstanceState) {
99        View root = inflater.inflate(R.layout.lb_search_fragment, container, false);
100
101        mSearchFrame = (RelativeLayout) root.findViewById(R.id.lb_search_frame);
102        mResultsFrame = (FrameLayout) root.findViewById(R.id.lb_results_frame);
103        mSearchBar = (SearchBar) mSearchFrame.findViewById(R.id.lb_search_bar);
104        mSearchBar.setSearchBarListener(new SearchBar.SearchBarListener() {
105            @Override
106            public void onSearchQueryChanged(String searchQuery) {
107                if (null != mProvider) {
108                    retrieveResults(searchQuery);
109                } else {
110                    mPendingQuery = searchQuery;
111                }
112            }
113        });
114        Bundle args = getArguments();
115        if (null != args) {
116            String query = args.getString(ARG_QUERY, "");
117            mSearchBar.setSearchQuery(query);
118        }
119
120        // Inject the RowsFragment in the results container
121        getChildFragmentManager().beginTransaction()
122                .replace(R.id.lb_results_container, mRowsFragment).commit();
123        return root;
124    }
125
126    /**
127     * Set the search provider, which is responsible for returning items given
128     * a search term
129     *
130     * @param searchResultProvider the search provider
131     */
132    public void setSearchResultProvider(SearchResultProvider searchResultProvider) {
133        mProvider = searchResultProvider;
134        onSetSearchResultProvider();
135    }
136
137    /**
138     * Sets an item selection listener.
139     * @param listener the item selection listener
140     */
141    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
142        mRowsFragment.setOnItemSelectedListener(listener);
143    }
144
145    /**
146     * Sets an item clicked listener.
147     */
148    public void setOnItemClickedListener(OnItemClickedListener listener) {
149        mRowsFragment.setOnItemClickedListener(listener);
150    }
151
152    /**
153     * Set the visibility of titles/hovercard of browse rows.
154     */
155    public void setExpand(boolean expand) {
156        mRowsFragment.setExpand(expand);
157    }
158
159    private void retrieveResults(String searchQuery) {
160        ObjectAdapter adapter = mProvider.results(searchQuery);
161        mRowsFragment.setAdapter(adapter);
162        mResultsFrame.setVisibility(View.VISIBLE);
163    }
164
165    private void onSetSearchResultProvider() {
166        executePendingQuery();
167    }
168
169    private void executePendingQuery() {
170        if (null != mPendingQuery) {
171            mHandler.post(new Runnable() {
172                @Override
173                public void run() {
174                    retrieveResults(mPendingQuery);
175                    mPendingQuery = null;
176                }
177            });
178        }
179    }
180
181}
182