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