Home | History | Annotate | Download | only in leanback
      1 package com.example.android.leanback;
      2 
      3 import static com.example.android.leanback.CardPresenter.CONTENT;
      4 import static com.example.android.leanback.CardPresenter.IMAGE;
      5 import static com.example.android.leanback.CardPresenter.TITLE;
      6 
      7 import android.content.Context;
      8 import android.content.Intent;
      9 import android.os.Bundle;
     10 import android.os.Handler;
     11 import android.support.annotation.Nullable;
     12 import android.support.v17.leanback.widget.ArrayObjectAdapter;
     13 import android.support.v17.leanback.widget.DiffCallback;
     14 import android.support.v17.leanback.widget.HeaderItem;
     15 import android.support.v17.leanback.widget.ImageCardView;
     16 import android.support.v17.leanback.widget.ListRow;
     17 import android.support.v17.leanback.widget.ListRowPresenter;
     18 import android.support.v17.leanback.widget.ObjectAdapter;
     19 import android.support.v17.leanback.widget.OnItemViewClickedListener;
     20 import android.support.v17.leanback.widget.Presenter;
     21 import android.support.v17.leanback.widget.Row;
     22 import android.support.v17.leanback.widget.RowPresenter;
     23 import android.support.v4.app.ActivityOptionsCompat;
     24 import android.support.v4.content.res.ResourcesCompat;
     25 import android.text.TextUtils;
     26 import android.util.Log;
     27 
     28 import java.util.ArrayList;
     29 
     30 public 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