Home | History | Annotate | Download | only in leanback
      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  */
     14 package com.example.android.leanback;
     15 
     16 import android.content.Context;
     17 import android.content.Intent;
     18 import android.graphics.Bitmap;
     19 import android.graphics.drawable.Drawable;
     20 import android.net.Uri;
     21 import android.os.Bundle;
     22 import android.os.Handler;
     23 import android.util.Log;
     24 import android.view.LayoutInflater;
     25 import android.view.View;
     26 import android.view.ViewGroup;
     27 
     28 import androidx.core.app.ActivityOptionsCompat;
     29 import androidx.core.content.res.ResourcesCompat;
     30 import androidx.leanback.app.DetailsFragmentBackgroundController;
     31 import androidx.leanback.media.MediaPlayerAdapter;
     32 import androidx.leanback.media.MediaPlayerGlue;
     33 import androidx.leanback.media.PlaybackGlue;
     34 import androidx.leanback.media.PlaybackTransportControlGlue;
     35 import androidx.leanback.widget.Action;
     36 import androidx.leanback.widget.ArrayObjectAdapter;
     37 import androidx.leanback.widget.ClassPresenterSelector;
     38 import androidx.leanback.widget.DetailsOverviewRow;
     39 import androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter;
     40 import androidx.leanback.widget.FullWidthDetailsOverviewSharedElementHelper;
     41 import androidx.leanback.widget.HeaderItem;
     42 import androidx.leanback.widget.ImageCardView;
     43 import androidx.leanback.widget.ListRow;
     44 import androidx.leanback.widget.ListRowPresenter;
     45 import androidx.leanback.widget.OnActionClickedListener;
     46 import androidx.leanback.widget.OnItemViewClickedListener;
     47 import androidx.leanback.widget.OnItemViewSelectedListener;
     48 import androidx.leanback.widget.Presenter;
     49 import androidx.leanback.widget.Row;
     50 import androidx.leanback.widget.RowPresenter;
     51 import androidx.leanback.widget.SparseArrayObjectAdapter;
     52 
     53 public class NewDetailsFragment extends androidx.leanback.app.DetailsFragment {
     54 
     55     private static final String TAG = "leanback.DetailsFragment";
     56     private static final String ITEM = "item";
     57 
     58     private static final int NUM_ROWS = 3;
     59     private ArrayObjectAdapter mRowsAdapter;
     60     private PhotoItem mPhotoItem;
     61     final CardPresenter cardPresenter = new CardPresenter();
     62 
     63     private static final int ACTION_PLAY = 1;
     64     private static final int ACTION_RENT = 2;
     65     private static final int ACTION_BUY = 3;
     66 
     67     private boolean TEST_SHARED_ELEMENT_TRANSITION = true;
     68     private boolean TEST_BACKGROUND_PLAYER;
     69 
     70     private static final long TIME_TO_LOAD_OVERVIEW_ROW_MS = 1000;
     71     private static final long TIME_TO_LOAD_RELATED_ROWS_MS = 2000;
     72 
     73     private Action mActionPlay;
     74     private Action mActionRent;
     75     private Action mActionBuy;
     76 
     77     private FullWidthDetailsOverviewSharedElementHelper mHelper;
     78     private BackgroundHelper mBackgroundHelper; // used to download bitmap async.
     79     private final DetailsFragmentBackgroundController mDetailsBackground =
     80             new DetailsFragmentBackgroundController(this);
     81 
     82     void setupTrailerVideo() {
     83         MediaPlayerGlue mediaPlayerGlue = new MediaPlayerGlue(getActivity());
     84         mDetailsBackground.setupVideoPlayback(mediaPlayerGlue);
     85         mediaPlayerGlue.setMode(MediaPlayerGlue.REPEAT_ONE);
     86         mediaPlayerGlue.setArtist("A Googler");
     87         mediaPlayerGlue.setTitle("Diving with Sharks Trailer");
     88         mediaPlayerGlue.setMediaSource(Uri.parse("android.resource://com.example.android.leanback/"
     89                 + "raw/browse"));
     90     }
     91 
     92     void setupMainVideo() {
     93         Context context = getActivity();
     94         MediaPlayerAdapter adapter = new MediaPlayerAdapter(context);
     95         PlaybackTransportControlGlue<MediaPlayerAdapter> mediaPlayerGlue =
     96                 new PlaybackTransportControlGlue(context, adapter);
     97         mDetailsBackground.setupVideoPlayback(mediaPlayerGlue);
     98         mediaPlayerGlue.setSubtitle("A Googler");
     99         mediaPlayerGlue.setTitle("Diving with Sharks");
    100         mediaPlayerGlue.getPlayerAdapter().setDataSource(Uri.parse(
    101                 "https://storage.googleapis.com/android-tv/Sample videos/April Fool's "
    102                         + "2013/Explore Treasure Mode with Google Maps.mp4"));
    103         mediaPlayerGlue.addPlayerCallback(new PlaybackGlue.PlayerCallback() {
    104             @Override
    105             public void onPreparedStateChanged(PlaybackGlue glue) {
    106                 super.onPreparedStateChanged(glue);
    107                 PlaybackTransportControlGlue controlGlue = (PlaybackTransportControlGlue) glue;
    108                 controlGlue.setSeekProvider(new PlaybackSeekDiskDataProvider(
    109                         controlGlue.getDuration(), 1000,
    110                         "/sdcard/seek/frame_%04d.jpg"));
    111             }
    112         });
    113     }
    114 
    115     @Override
    116     public void onCreate(Bundle savedInstanceState) {
    117         Log.i(TAG, "onCreate");
    118         super.onCreate(savedInstanceState);
    119 
    120         mBackgroundHelper = new BackgroundHelper(getActivity());
    121         mDetailsBackground.enableParallax();
    122         if (TEST_BACKGROUND_PLAYER) {
    123             if (MovieData.sStatus == MovieData.STATUS_INIT) {
    124                 // not own/rented, play trailer
    125                 setupTrailerVideo();
    126             } else {
    127                 // bought or rented, play the main content
    128                 setupMainVideo();
    129                 // hide details main ui
    130                 mDetailsBackground.switchToVideo();
    131             }
    132         }
    133 
    134         final Context context = getActivity();
    135         setBadgeDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_title,
    136                 context.getTheme()));
    137         setTitle("Leanback Sample App");
    138         if (!TEST_BACKGROUND_PLAYER) {
    139             setOnSearchClickedListener(new View.OnClickListener() {
    140                 @Override
    141                 public void onClick(View view) {
    142                     Intent intent = new Intent(getActivity(), SearchActivity.class);
    143                     startActivity(intent);
    144                 }
    145             });
    146         }
    147 
    148         mActionPlay = new Action(ACTION_PLAY, "Play");
    149         mActionRent = new Action(ACTION_RENT, "Rent", "$3.99", ResourcesCompat.getDrawable(
    150                 context.getResources(), R.drawable.ic_action_a, context.getTheme()));
    151         mActionBuy = new Action(ACTION_BUY, "Buy $9.99");
    152 
    153         ClassPresenterSelector ps = new ClassPresenterSelector();
    154         FullWidthDetailsOverviewRowPresenter dorPresenter =
    155                 new FullWidthDetailsOverviewRowPresenter(new DetailsDescriptionPresenter());
    156         dorPresenter.setOnActionClickedListener(new OnActionClickedListener() {
    157             @Override
    158             public void onActionClicked(Action action) {
    159                 final Context context = getActivity();
    160                 DetailsOverviewRow dor = (DetailsOverviewRow) mRowsAdapter.get(0);
    161                 if (action.getId() == ACTION_BUY) {
    162                     // on the UI thread, we can modify actions adapter directly
    163                     SparseArrayObjectAdapter actions = (SparseArrayObjectAdapter)
    164                             dor.getActionsAdapter();
    165                     actions.set(ACTION_PLAY, mActionPlay);
    166                     actions.clear(ACTION_RENT);
    167                     actions.clear(ACTION_BUY);
    168                     boolean previousRented = MovieData.sStatus == MovieData.STATUS_RENTED;
    169                     MovieData.sStatus = MovieData.STATUS_OWN;
    170                     dor.setItem(getDisplayTitle(mPhotoItem.getTitle()));
    171                     dor.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
    172                             R.drawable.details_img_16x9, context.getTheme()));
    173                     if (TEST_BACKGROUND_PLAYER) {
    174                         if (!previousRented) {
    175                             setupMainVideo();
    176                             mDetailsBackground.switchToVideo();
    177                         }
    178                     } else {
    179                         Intent intent = new Intent(context, PlaybackActivity.class);
    180                         getActivity().startActivity(intent);
    181                     }
    182                 } else if (action.getId() == ACTION_RENT) {
    183                     // on the UI thread, we can modify actions adapter directly
    184                     SparseArrayObjectAdapter actions = (SparseArrayObjectAdapter)
    185                             dor.getActionsAdapter();
    186                     actions.set(ACTION_PLAY, mActionPlay);
    187                     actions.clear(ACTION_RENT);
    188                     MovieData.sStatus = MovieData.STATUS_RENTED;
    189                     dor.setItem(getDisplayTitle(mPhotoItem.getTitle()));
    190                     if (TEST_BACKGROUND_PLAYER) {
    191                         setupMainVideo();
    192                         mDetailsBackground.switchToVideo();
    193                     } else {
    194                         Intent intent = new Intent(context, PlaybackActivity.class);
    195                         getActivity().startActivity(intent);
    196                     }
    197                 } else if (action.getId() == ACTION_PLAY) {
    198                     if (TEST_BACKGROUND_PLAYER) {
    199                         mDetailsBackground.switchToVideo();
    200                     } else {
    201                         Intent intent = new Intent(context, PlaybackActivity.class);
    202                         getActivity().startActivity(intent);
    203                     }
    204                 }
    205             }
    206         });
    207 
    208         ps.addClassPresenter(DetailsOverviewRow.class, dorPresenter);
    209         ps.addClassPresenter(ListRow.class, new ListRowPresenter());
    210 
    211         mRowsAdapter = new ArrayObjectAdapter(ps);
    212         updateAdapter();
    213 
    214         setOnItemViewClickedListener(new OnItemViewClickedListener() {
    215             @Override
    216             public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
    217                     RowPresenter.ViewHolder rowViewHolder, Row row) {
    218                 Log.i(TAG, "onItemClicked: " + item + " row " + row);
    219                 if (item instanceof PhotoItem) {
    220                     Intent intent = new Intent(getActivity(), DetailsActivity.class);
    221                     intent.putExtra(DetailsActivity.EXTRA_ITEM, (PhotoItem) item);
    222 
    223                     Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
    224                             getActivity(),
    225                             ((ImageCardView) itemViewHolder.view).getMainImageView(),
    226                             DetailsActivity.SHARED_ELEMENT_NAME).toBundle();
    227                     getActivity().startActivity(intent, bundle);
    228                 }
    229             }
    230         });
    231         setOnItemViewSelectedListener(new OnItemViewSelectedListener() {
    232             @Override
    233             public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
    234                     RowPresenter.ViewHolder rowViewHolder, Row row) {
    235                 Log.i(TAG, "onItemSelected: " + item + " row " + row);
    236             }
    237         });
    238 
    239         if (TEST_SHARED_ELEMENT_TRANSITION) {
    240             mHelper = new FullWidthDetailsOverviewSharedElementHelper();
    241             mHelper.setSharedElementEnterTransition(getActivity(),
    242                     DetailsActivity.SHARED_ELEMENT_NAME);
    243             dorPresenter.setListener(mHelper);
    244             dorPresenter.setParticipatingEntranceTransition(false);
    245         } else {
    246             dorPresenter.setParticipatingEntranceTransition(true);
    247         }
    248     }
    249 
    250     @Override
    251     public View onCreateView(LayoutInflater inflater, ViewGroup container,
    252             Bundle savedInstanceState) {
    253         View view = super.onCreateView(inflater, container, savedInstanceState);
    254         return view;
    255     }
    256 
    257     public void setBackgroundVideo(boolean backgroundVideo) {
    258         TEST_BACKGROUND_PLAYER = backgroundVideo;
    259     }
    260 
    261     public void setItem(PhotoItem photoItem) {
    262         mPhotoItem = photoItem;
    263         updateAdapter();
    264     }
    265 
    266     static String getDisplayTitle(String title) {
    267         switch (MovieData.sStatus) {
    268             case MovieData.STATUS_OWN:
    269                 title = title + "(Owned)";
    270                 break;
    271             case MovieData.STATUS_RENTED:
    272                 title = title + "(Rented)";
    273                 break;
    274             case MovieData.STATUS_INIT:
    275             default:
    276         }
    277         return title;
    278     }
    279 
    280     void updateAdapter() {
    281         if (mRowsAdapter == null) {
    282             return;
    283         }
    284         mRowsAdapter.clear();
    285         new Handler().postDelayed(new Runnable() {
    286             @Override
    287             public void run() {
    288                 final Context context = getActivity();
    289                 if (context == null) {
    290                     return;
    291                 }
    292 
    293                 DetailsOverviewRow dor = new DetailsOverviewRow(
    294                         getDisplayTitle(mPhotoItem.getTitle()));
    295                 dor.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
    296                         mPhotoItem.getImageResourceId(), context.getTheme()));
    297                 SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter();
    298                 switch (MovieData.sStatus) {
    299                     case MovieData.STATUS_INIT:
    300                         adapter.set(ACTION_RENT, mActionRent);
    301                         adapter.set(ACTION_BUY, mActionBuy);
    302                         break;
    303                     case MovieData.STATUS_OWN:
    304                         adapter.set(ACTION_PLAY, mActionPlay);
    305                         break;
    306                     case MovieData.STATUS_RENTED:
    307                         adapter.set(ACTION_PLAY, mActionPlay);
    308                         adapter.set(ACTION_BUY, mActionBuy);
    309                         break;
    310                 }
    311                 // one line text with icon
    312                 Drawable d = ResourcesCompat.getDrawable(context.getResources(),
    313                         R.drawable.ic_action_a, context.getTheme());
    314                 adapter.set(202, new Action(202, "Top", null, d));
    315                 dor.setActionsAdapter(adapter);
    316                 mRowsAdapter.add(0, dor);
    317                 setSelectedPosition(0, true);
    318                 if (TEST_SHARED_ELEMENT_TRANSITION) {
    319                     if (mHelper != null && !mHelper.getAutoStartSharedElementTransition()) {
    320                         mHelper.startPostponedEnterTransition();
    321                     }
    322                 }
    323             }
    324         }, TIME_TO_LOAD_OVERVIEW_ROW_MS);
    325 
    326         new Handler().postDelayed(new Runnable() {
    327             @Override
    328             public void run() {
    329                 if (getActivity() == null) {
    330                     return;
    331                 }
    332                 for (int i = 0; i < NUM_ROWS; ++i) {
    333                     ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
    334                     listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
    335                     listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
    336                     listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_3));
    337                     listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_4));
    338                     HeaderItem header = new HeaderItem(i, "Row " + i);
    339                     mRowsAdapter.add(new ListRow(header, listRowAdapter));
    340                 }
    341             }
    342         }, TIME_TO_LOAD_RELATED_ROWS_MS);
    343         setAdapter(mRowsAdapter);
    344     }
    345 
    346     @Override
    347     public void onStart() {
    348         super.onStart();
    349 
    350         // Restore background drawable in onStart():
    351         mBackgroundHelper.loadBitmap(R.drawable.spiderman,
    352                 new BackgroundHelper.BitmapLoadCallback() {
    353                     @Override
    354                     public void onBitmapLoaded(Bitmap bitmap) {
    355                         mDetailsBackground.setCoverBitmap(bitmap);
    356                     }
    357                 });
    358     }
    359 
    360     @Override
    361     public void onStop() {
    362         mDetailsBackground.setCoverBitmap(null);
    363         super.onStop();
    364     }
    365 }
    366