1 // CHECKSTYLE:OFF Generated code
2 /* This file is auto-generated from SearchFragment.java.  DO NOT MODIFY. */
3 
4 package com.example.android.leanback;
5 
6 import static com.example.android.leanback.CardPresenter.CONTENT;
7 import static com.example.android.leanback.CardPresenter.IMAGE;
8 import static com.example.android.leanback.CardPresenter.TITLE;
9 
10 import android.content.Context;
11 import android.content.Intent;
12 import android.os.Bundle;
13 import android.os.Handler;
14 import android.text.TextUtils;
15 import android.util.Log;
16 
17 import androidx.core.app.ActivityOptionsCompat;
18 import androidx.core.content.res.ResourcesCompat;
19 import androidx.leanback.widget.ArrayObjectAdapter;
20 import androidx.leanback.widget.DiffCallback;
21 import androidx.leanback.widget.HeaderItem;
22 import androidx.leanback.widget.ImageCardView;
23 import androidx.leanback.widget.ListRow;
24 import androidx.leanback.widget.ListRowPresenter;
25 import androidx.leanback.widget.ObjectAdapter;
26 import androidx.leanback.widget.OnItemViewClickedListener;
27 import androidx.leanback.widget.Presenter;
28 import androidx.leanback.widget.Row;
29 import androidx.leanback.widget.RowPresenter;
30 
31 import org.jspecify.annotations.NonNull;
32 import org.jspecify.annotations.Nullable;
33 
34 import java.util.ArrayList;
35 
36 public class SearchSupportFragment extends androidx.leanback.app.SearchSupportFragment
37         implements androidx.leanback.app.SearchSupportFragment.SearchResultProvider {
38     private static final String TAG = "leanback.SearchSupportFragment";
39     private static final int NUM_ROWS = 3;
40     private static final int SEARCH_DELAY_MS = 1000;
41 
42     private ArrayObjectAdapter mRowsAdapter;
43     private Handler mHandler = new Handler();
44     private String mQuery;
45 
46     // Flag to represent if data set one is presented in the fragment
47     private boolean mIsDataSetOnePresented;
48 
49     // Adapter for first row
50     private ArrayObjectAdapter mFirstRowAdapter;
51 
52     // The diff callback which defines the standard to judge if two items are the same or if
53     // two items have the same content.
54     private DiffCallback<PhotoItem> mDiffCallback = new DiffCallback<PhotoItem>() {
55 
56         // when two photo items have the same id, they are the same from adapter's
57         // perspective
58         @Override
59         public boolean areItemsTheSame(@NonNull PhotoItem oldItem, @NonNull PhotoItem newItem) {
60             return oldItem.getId() == newItem.getId();
61         }
62 
63         // when two photo items is equal to each other (based on the equal method defined in
64         // PhotoItem), they have the same content.
65         @Override
66         public boolean areContentsTheSame(@NonNull PhotoItem oldItem, @NonNull PhotoItem newItem) {
67             return oldItem.equals(newItem);
68         }
69 
70         @Override
71         public @Nullable Object getChangePayload(@NonNull PhotoItem oldItem,
72                 @NonNull PhotoItem newItem) {
73             Bundle diff = new Bundle();
74             if (oldItem.getImageResourceId()
75                     != newItem.getImageResourceId()) {
76                 diff.putLong(IMAGE, newItem.getImageResourceId());
77             }
78 
79             if (oldItem.getTitle() != null && newItem.getTitle() != null
80                     && !oldItem.getTitle().equals(newItem.getTitle())) {
81                 diff.putString(TITLE, newItem.getTitle());
82             }
83 
84             if (oldItem.getContent() != null && newItem.getContent() != null
85                     && !oldItem.getContent().equals(newItem.getContent())) {
86                 diff.putString(CONTENT, newItem.getContent());
87             }
88             return diff;
89         }
90     };
91 
92     @Override
onCreate(Bundle savedInstanceState)93     public void onCreate(Bundle savedInstanceState) {
94         super.onCreate(savedInstanceState);
95 
96         mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
97 
98         final Context context = getActivity();
99         setBadgeDrawable(ResourcesCompat.getDrawable(context.getResources(),
100                 R.drawable.ic_title, context.getTheme()));
101         setTitle("Leanback Sample App");
102         setSearchResultProvider(this);
103         setOnItemViewClickedListener(new ItemViewClickedListener());
104     }
105 
106     @Override
getResultsAdapter()107     public ObjectAdapter getResultsAdapter() {
108         return mRowsAdapter;
109     }
110 
111     @Override
onQueryTextChange(String newQuery)112     public boolean onQueryTextChange(String newQuery) {
113         Log.i(TAG, String.format("Search Query Text Change %s", newQuery));
114         mRowsAdapter.clear();
115         loadQuery(newQuery);
116         return true;
117     }
118 
119     @Override
onQueryTextSubmit(String query)120     public boolean onQueryTextSubmit(String query) {
121         Log.i(TAG, String.format("Search Query Text Submit %s", query));
122         mRowsAdapter.clear();
123         loadQuery(query);
124         return true;
125     }
126 
loadQuery(String query)127     private void loadQuery(String query) {
128         mQuery = query;
129         mHandler.removeCallbacks(mDelayedLoad);
130         if (!TextUtils.isEmpty(query) && !query.equals("nil")) {
131             mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS);
132         }
133     }
134 
loadRows()135     private void loadRows() {
136         HeaderItem header = new HeaderItem(0, mQuery + " results row " + 0);
137 
138         // Every time when the query event is fired, we will update the fake search result in the
139         // first row based on the flag mIsDataSetOnePresented flag.
140         // Also the first row adapter will only be created once so the animation will be triggered
141         // when the items in the adapter changed.
142         if (!mIsDataSetOnePresented) {
143             if (mFirstRowAdapter == null) {
144                 mFirstRowAdapter = createFirstListRowAdapter();
145             } else {
146                 mFirstRowAdapter.setItems(createDataSetOneDebug(), mDiffCallback);
147             }
148             mIsDataSetOnePresented = true;
149         } else {
150             mFirstRowAdapter.setItems(createDataSetTwoDebug(), mDiffCallback);
151             mIsDataSetOnePresented = false;
152         }
153         mRowsAdapter.add(new ListRow(header, mFirstRowAdapter));
154         for (int i = 1; i < NUM_ROWS + 1; ++i) {
155             ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
156             listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
157             listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
158             header = new HeaderItem(i, mQuery + " results row " + i);
159             mRowsAdapter.add(new ListRow(header, listRowAdapter));
160         }
161     }
162 
163     private Runnable mDelayedLoad = new Runnable() {
164         @Override
165         public void run() {
166             loadRows();
167         }
168     };
169 
170     private final class ItemViewClickedListener implements OnItemViewClickedListener {
171         @Override
onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row)172         public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
173                 RowPresenter.ViewHolder rowViewHolder, Row row) {
174             Intent intent = new Intent(getActivity(), DetailsSupportActivity.class);
175             intent.putExtra(DetailsSupportActivity.EXTRA_ITEM, (PhotoItem) item);
176 
177             Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
178                     getActivity(),
179                     ((ImageCardView) itemViewHolder.view).getMainImageView(),
180                     DetailsSupportActivity.SHARED_ELEMENT_NAME).toBundle();
181             getActivity().startActivity(intent, bundle);
182         }
183     }
184 
185 
createFirstListRowAdapter()186     private ArrayObjectAdapter createFirstListRowAdapter() {
187         ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
188         listRowAdapter.setItems(createDataSetOneDebug(), mDiffCallback);
189         mIsDataSetOnePresented = true;
190         return listRowAdapter;
191     }
192 
createDataSetOneDebug()193     private ArrayList<PhotoItem> createDataSetOneDebug() {
194         ArrayList<PhotoItem> photoItems = new ArrayList<>();
195         photoItems.add(new PhotoItem(
196                 "Hello world",
197                 R.drawable.gallery_photo_1,
198                 1));
199         return photoItems;
200     }
201 
202     /**
203      * Create a new data set (data set one) for the last row of this browse fragment. It will be
204      * changed by another set of data when user click one of the photo items in the list.
205      * Different with other rows in the browsing fragment, the photo item in last row all have been
206      * allocated with a unique id. And the id will be used to jduge if two photo items are the same
207      * or not.
208      *
209      * @return List of photoItem
210      */
createDataSetTwoDebug()211     private ArrayList<PhotoItem> createDataSetTwoDebug() {
212         ArrayList<PhotoItem> photoItems = new ArrayList<>();
213         photoItems.add(new PhotoItem(
214                 "Hello world Hello world",
215                 R.drawable.gallery_photo_1,
216                 1));
217         return photoItems;
218     }
219 }
220