SearchFragment.java revision 08a38559a3751252fc8a1f36db0a431508a8f7d5
1package com.example.android.leanback;
2
3import static com.example.android.leanback.CardPresenter.CONTENT;
4import static com.example.android.leanback.CardPresenter.IMAGE;
5import static com.example.android.leanback.CardPresenter.TITLE;
6
7import android.content.Context;
8import android.content.Intent;
9import android.os.Bundle;
10import android.os.Handler;
11import android.support.annotation.Nullable;
12import android.support.v17.leanback.widget.ArrayObjectAdapter;
13import android.support.v17.leanback.widget.DiffCallback;
14import android.support.v17.leanback.widget.HeaderItem;
15import android.support.v17.leanback.widget.ImageCardView;
16import android.support.v17.leanback.widget.ListRow;
17import android.support.v17.leanback.widget.ListRowPresenter;
18import android.support.v17.leanback.widget.ObjectAdapter;
19import android.support.v17.leanback.widget.OnItemViewClickedListener;
20import android.support.v17.leanback.widget.Presenter;
21import android.support.v17.leanback.widget.Row;
22import android.support.v17.leanback.widget.RowPresenter;
23import android.support.v4.app.ActivityOptionsCompat;
24import android.support.v4.content.res.ResourcesCompat;
25import android.text.TextUtils;
26import android.util.Log;
27
28import java.util.ArrayList;
29
30public class SearchFragment extends android.support.v17.leanback.app.SearchFragment
31        implements android.support.v17.leanback.app.SearchFragment.SearchResultProvider {
32    private static final String TAG = "leanback.SearchFragment";
33    private static final int NUM_ROWS = 3;
34    private static final int SEARCH_DELAY_MS = 1000;
35
36    private ArrayObjectAdapter mRowsAdapter;
37    private Handler mHandler = new Handler();
38    private String mQuery;
39
40    // Flag to represent if data set one is presented in the fragment
41    private boolean mIsDataSetOnePresented;
42
43    // Adapter for first row
44    private ArrayObjectAdapter mFirstRowAdapter;
45
46    // The diff callback which defines the standard to judge if two items are the same or if
47    // two items have the same content.
48    private DiffCallback<PhotoItem> mDiffCallback = new DiffCallback<PhotoItem>() {
49
50        // when two photo items have the same id, they are the same from adapter's
51        // perspective
52        @Override
53        public boolean areItemsTheSame(PhotoItem oldItem, PhotoItem newItem) {
54            return oldItem.getId() == newItem.getId();
55        }
56
57        // when two photo items is equal to each other (based on the equal method defined in
58        // PhotoItem), they have the same content.
59        @Override
60        public boolean areContentsTheSame(PhotoItem oldItem, PhotoItem newItem) {
61            return oldItem.equals(newItem);
62        }
63
64        @Nullable
65        @Override
66        public Object getChangePayload(PhotoItem oldItem, PhotoItem newItem) {
67            Bundle diff = new Bundle();
68            if (oldItem.getImageResourceId()
69                    != newItem.getImageResourceId()) {
70                diff.putLong(IMAGE, newItem.getImageResourceId());
71            }
72
73            if (oldItem.getTitle() != null && newItem.getTitle() != null
74                    && !oldItem.getTitle().equals(newItem.getTitle())) {
75                diff.putString(TITLE, newItem.getTitle());
76            }
77
78            if (oldItem.getContent() != null && newItem.getContent() != null
79                    && !oldItem.getContent().equals(newItem.getContent())) {
80                diff.putString(CONTENT, newItem.getContent());
81            }
82            return diff;
83        }
84    };
85
86    @Override
87    public void onCreate(Bundle savedInstanceState) {
88        super.onCreate(savedInstanceState);
89
90        mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
91
92        final Context context = getActivity();
93        setBadgeDrawable(ResourcesCompat.getDrawable(context.getResources(),
94                R.drawable.ic_title, context.getTheme()));
95        setTitle("Leanback Sample App");
96        setSearchResultProvider(this);
97        setOnItemViewClickedListener(new ItemViewClickedListener());
98    }
99
100    @Override
101    public ObjectAdapter getResultsAdapter() {
102        return mRowsAdapter;
103    }
104
105    @Override
106    public boolean onQueryTextChange(String newQuery) {
107        Log.i(TAG, String.format("Search Query Text Change %s", newQuery));
108        mRowsAdapter.clear();
109        loadQuery(newQuery);
110        return true;
111    }
112
113    @Override
114    public boolean onQueryTextSubmit(String query) {
115        Log.i(TAG, String.format("Search Query Text Submit %s", query));
116        mRowsAdapter.clear();
117        loadQuery(query);
118        return true;
119    }
120
121    private void loadQuery(String query) {
122        mQuery = query;
123        mHandler.removeCallbacks(mDelayedLoad);
124        if (!TextUtils.isEmpty(query) && !query.equals("nil")) {
125            mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS);
126        }
127    }
128
129    private void loadRows() {
130        HeaderItem header = new HeaderItem(0, mQuery + " results row " + 0);
131
132        // Every time when the query event is fired, we will update the fake search result in the
133        // first row based on the flag mIsDataSetOnePresented flag.
134        // Also the first row adapter will only be created once so the animation will be triggered
135        // when the items in the adapter changed.
136        if (!mIsDataSetOnePresented) {
137            if (mFirstRowAdapter == null) {
138                mFirstRowAdapter = createFirstListRowAdapter();
139            } else {
140                mFirstRowAdapter.setItems(createDataSetOneDebug(), mDiffCallback);
141            }
142            mIsDataSetOnePresented = true;
143        } else {
144            mFirstRowAdapter.setItems(createDataSetTwoDebug(), mDiffCallback);
145            mIsDataSetOnePresented = false;
146        }
147        mRowsAdapter.add(new ListRow(header, mFirstRowAdapter));
148        for (int i = 1; i < NUM_ROWS + 1; ++i) {
149            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
150            listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
151            listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
152            header = new HeaderItem(i, mQuery + " results row " + i);
153            mRowsAdapter.add(new ListRow(header, listRowAdapter));
154        }
155    }
156
157    private Runnable mDelayedLoad = new Runnable() {
158        @Override
159        public void run() {
160            loadRows();
161        }
162    };
163
164    private final class ItemViewClickedListener implements OnItemViewClickedListener {
165        @Override
166        public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
167                RowPresenter.ViewHolder rowViewHolder, Row row) {
168            Intent intent = new Intent(getActivity(), DetailsActivity.class);
169            intent.putExtra(DetailsActivity.EXTRA_ITEM, (PhotoItem) item);
170
171            Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
172                    getActivity(),
173                    ((ImageCardView) itemViewHolder.view).getMainImageView(),
174                    DetailsActivity.SHARED_ELEMENT_NAME).toBundle();
175            getActivity().startActivity(intent, bundle);
176        }
177    }
178
179
180    private ArrayObjectAdapter createFirstListRowAdapter() {
181        ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
182        listRowAdapter.setItems(createDataSetOneDebug(), mDiffCallback);
183        mIsDataSetOnePresented = true;
184        return listRowAdapter;
185    }
186
187    /**
188     * Create a data set (data set one) for the last row of this browse fragment. It will be
189     * changed by another set of data when user click one of the photo items in the list.
190     * Different with other rows in the browsing fragment, the photo item in last row all have been
191     * allocated with a unique id. And the id will be used to jduge if two photo items are the same
192     * or not.
193     *
194     * @return List of photoItem
195     */
196    private ArrayList<PhotoItem> createDataSetOne() {
197        ArrayList<PhotoItem> photoItems = new ArrayList<>();
198        photoItems.add(new PhotoItem(
199                "Hello world",
200                R.drawable.gallery_photo_1,
201                1));
202        photoItems.add(new PhotoItem(
203                "This is a test",
204                "Only a test",
205                R.drawable.gallery_photo_2,
206                2));
207        photoItems.add(new PhotoItem(
208                "Android TV",
209                "by Google",
210                R.drawable.gallery_photo_3,
211                3));
212        photoItems.add(new PhotoItem(
213                "Leanback",
214                R.drawable.gallery_photo_4,
215                4));
216        photoItems.add(new PhotoItem(
217                "GuidedStep (Slide left/right)",
218                R.drawable.gallery_photo_5,
219                5));
220        photoItems.add(new PhotoItem(
221                "GuidedStep (Slide bottom up)",
222                "Open GuidedStepFragment",
223                R.drawable.gallery_photo_6,
224                6));
225        photoItems.add(new PhotoItem(
226                "Android TV",
227                "open RowsActivity",
228                R.drawable.gallery_photo_7,
229                7));
230        photoItems.add(new PhotoItem(
231                "Leanback",
232                "open BrowseActivity",
233                R.drawable.gallery_photo_8,
234                8));
235        photoItems.add(new PhotoItem(
236                "Hello world",
237                R.drawable.gallery_photo_1,
238                1));
239        photoItems.add(new PhotoItem(
240                "This is a test",
241                "Only a test",
242                R.drawable.gallery_photo_2,
243                2));
244        photoItems.add(new PhotoItem(
245                "Android TV",
246                "by Google",
247                R.drawable.gallery_photo_3,
248                3));
249        photoItems.add(new PhotoItem(
250                "Leanback",
251                R.drawable.gallery_photo_4,
252                4));
253        return photoItems;
254    }
255
256    /**
257     * Create a new data set (data set one) for the last row of this browse fragment. It will be
258     * changed by another set of data when user click one of the photo items in the list.
259     * Different with other rows in the browsing fragment, the photo item in last row all have been
260     * allocated with a unique id. And the id will be used to jduge if two photo items are the same
261     * or not.
262     *
263     * @return List of photoItem
264     */
265    private ArrayList<PhotoItem> createDataSetTwo() {
266        ArrayList<PhotoItem> photoItems = new ArrayList<>();
267        photoItems.add(new PhotoItem(
268                "This is a test",
269                "Only a test",
270                R.drawable.gallery_photo_2,
271                2));
272        photoItems.add(new PhotoItem(
273                "Hello world",
274                R.drawable.gallery_photo_1,
275                1));
276        photoItems.add(new PhotoItem(
277                "Leanback",
278                R.drawable.gallery_photo_4,
279                4));
280        photoItems.add(new PhotoItem(
281                "Android TV",
282                "by Google",
283                R.drawable.gallery_photo_3,
284                3));
285        photoItems.add(new PhotoItem(
286                "change title",
287                R.drawable.gallery_photo_5,
288                5));
289        photoItems.add(new PhotoItem(
290                "GuidedStep (Slide bottom up)",
291                "change comment",
292                R.drawable.gallery_photo_6,
293                6));
294        photoItems.add(new PhotoItem(
295                "Android TV",
296                R.drawable.gallery_photo_7,
297                7));
298        photoItems.add(new PhotoItem(
299                "Leanback",
300                "open BrowseActivity",
301                R.drawable.gallery_photo_7,
302                8));
303        photoItems.add(new PhotoItem(
304                "Hello world",
305                R.drawable.gallery_photo_1,
306                10));
307        photoItems.add(new PhotoItem(
308                "This is a test",
309                "Only a test",
310                R.drawable.gallery_photo_2,
311                20));
312        photoItems.add(new PhotoItem(
313                "Android TV",
314                "by Google",
315                R.drawable.gallery_photo_3,
316                30));
317        photoItems.add(new PhotoItem(
318                "Leanback",
319                R.drawable.gallery_photo_4,
320                40));
321        return photoItems;
322    }
323
324
325    private ArrayList<PhotoItem> createDataSetOneDebug() {
326        ArrayList<PhotoItem> photoItems = new ArrayList<>();
327        photoItems.add(new PhotoItem(
328                "Hello world",
329                R.drawable.gallery_photo_1,
330                1));
331        return photoItems;
332    }
333
334    /**
335     * Create a new data set (data set one) for the last row of this browse fragment. It will be
336     * changed by another set of data when user click one of the photo items in the list.
337     * Different with other rows in the browsing fragment, the photo item in last row all have been
338     * allocated with a unique id. And the id will be used to jduge if two photo items are the same
339     * or not.
340     *
341     * @return List of photoItem
342     */
343    private ArrayList<PhotoItem> createDataSetTwoDebug() {
344        ArrayList<PhotoItem> photoItems = new ArrayList<>();
345        photoItems.add(new PhotoItem(
346                "Hello world Hello world",
347                R.drawable.gallery_photo_1,
348                1));
349        return photoItems;
350    }
351}
352