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 com.example.android.leanback;
15
16import android.content.Context;
17import android.content.Intent;
18import android.graphics.Bitmap;
19import android.graphics.drawable.Drawable;
20import android.net.Uri;
21import android.os.Bundle;
22import android.os.Handler;
23import android.util.Log;
24import android.view.LayoutInflater;
25import android.view.View;
26import android.view.ViewGroup;
27
28import androidx.core.app.ActivityOptionsCompat;
29import androidx.core.content.res.ResourcesCompat;
30import androidx.leanback.app.DetailsFragmentBackgroundController;
31import androidx.leanback.media.MediaPlayerAdapter;
32import androidx.leanback.media.MediaPlayerGlue;
33import androidx.leanback.media.PlaybackGlue;
34import androidx.leanback.media.PlaybackTransportControlGlue;
35import androidx.leanback.widget.Action;
36import androidx.leanback.widget.ArrayObjectAdapter;
37import androidx.leanback.widget.ClassPresenterSelector;
38import androidx.leanback.widget.DetailsOverviewRow;
39import androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter;
40import androidx.leanback.widget.FullWidthDetailsOverviewSharedElementHelper;
41import androidx.leanback.widget.HeaderItem;
42import androidx.leanback.widget.ImageCardView;
43import androidx.leanback.widget.ListRow;
44import androidx.leanback.widget.ListRowPresenter;
45import androidx.leanback.widget.OnActionClickedListener;
46import androidx.leanback.widget.OnItemViewClickedListener;
47import androidx.leanback.widget.OnItemViewSelectedListener;
48import androidx.leanback.widget.Presenter;
49import androidx.leanback.widget.Row;
50import androidx.leanback.widget.RowPresenter;
51import androidx.leanback.widget.SparseArrayObjectAdapter;
52
53public 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