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 
15 package com.example.android.tvleanback.ui;
16 
17 import android.app.NotificationManager;
18 import android.content.Context;
19 import android.content.Intent;
20 import android.graphics.drawable.Drawable;
21 import android.net.Uri;
22 import android.os.Bundle;
23 import android.support.v17.leanback.app.BackgroundManager;
24 import android.support.v17.leanback.widget.Action;
25 import android.support.v17.leanback.widget.ArrayObjectAdapter;
26 import android.support.v17.leanback.widget.ClassPresenterSelector;
27 import android.support.v17.leanback.widget.DetailsOverviewRow;
28 import android.support.v17.leanback.widget.DetailsOverviewRowPresenter;
29 import android.support.v17.leanback.widget.HeaderItem;
30 import android.support.v17.leanback.widget.ImageCardView;
31 import android.support.v17.leanback.widget.ListRow;
32 import android.support.v17.leanback.widget.ListRowPresenter;
33 import android.support.v17.leanback.widget.OnActionClickedListener;
34 import android.support.v17.leanback.widget.OnItemViewClickedListener;
35 import android.support.v17.leanback.widget.Presenter;
36 import android.support.v17.leanback.widget.Row;
37 import android.support.v17.leanback.widget.RowPresenter;
38 import android.support.v4.app.ActivityOptionsCompat;
39 import android.util.DisplayMetrics;
40 import android.util.Log;
41 import android.widget.Toast;
42 
43 
44 import com.bumptech.glide.Glide;
45 import com.bumptech.glide.load.resource.drawable.GlideDrawable;
46 import com.bumptech.glide.request.animation.GlideAnimation;
47 import com.bumptech.glide.request.target.SimpleTarget;
48 
49 import com.example.android.tvleanback.R;
50 import com.example.android.tvleanback.Utils;
51 import com.example.android.tvleanback.data.VideoProvider;
52 import com.example.android.tvleanback.model.Movie;
53 import com.example.android.tvleanback.presenter.CardPresenter;
54 import com.example.android.tvleanback.presenter.DetailsDescriptionPresenter;
55 
56 import java.util.HashMap;
57 import java.util.List;
58 import java.util.Map;
59 
60 /*
61  * LeanbackDetailsFragment extends DetailsFragment, a Wrapper fragment for leanback details screens.
62  * It shows a detailed view of video and its meta plus related videos.
63  */
64 public class MovieDetailsFragment extends android.support.v17.leanback.app.DetailsFragment {
65     private static final String TAG = "DetailsFragment";
66 
67     private static final int ACTION_WATCH_TRAILER = 1;
68     private static final int ACTION_RENT = 2;
69     private static final int ACTION_BUY = 3;
70 
71     private static final int DETAIL_THUMB_WIDTH = 274;
72     private static final int DETAIL_THUMB_HEIGHT = 274;
73 
74     private static final int NO_NOTIFICATION = -1;
75 
76     private Movie mSelectedMovie;
77 
78     private ArrayObjectAdapter mAdapter;
79     private ClassPresenterSelector mPresenterSelector;
80 
81     private BackgroundManager mBackgroundManager;
82     private Drawable mDefaultBackground;
83     private DisplayMetrics mMetrics;
84 
85     @Override
onCreate(Bundle savedInstanceState)86     public void onCreate(Bundle savedInstanceState) {
87         Log.d(TAG, "onCreate DetailsFragment");
88         super.onCreate(savedInstanceState);
89 
90         prepareBackgroundManager();
91 
92         mSelectedMovie = (Movie) getActivity().getIntent()
93                 .getParcelableExtra(MovieDetailsActivity.MOVIE);
94         if (mSelectedMovie != null || checkGlobalSearchIntent()) {
95             removeNotification(getActivity().getIntent()
96                     .getIntExtra(MovieDetailsActivity.NOTIFICATION_ID, NO_NOTIFICATION));
97             setupAdapter();
98             setupDetailsOverviewRow();
99             setupDetailsOverviewRowPresenter();
100             setupMovieListRow();
101             setupMovieListRowPresenter();
102             updateBackground(mSelectedMovie.getBackgroundImageUrl());
103             setOnItemViewClickedListener(new ItemViewClickedListener());
104         } else {
105             Intent intent = new Intent(getActivity(), MainActivity.class);
106             startActivity(intent);
107         }
108     }
109 
removeNotification(int notificationId)110     private void removeNotification(int notificationId) {
111         if (notificationId != NO_NOTIFICATION) {
112             NotificationManager notificationManager = (NotificationManager) getActivity()
113                     .getSystemService(Context.NOTIFICATION_SERVICE);
114             notificationManager.cancel(notificationId);
115         }
116     }
117 
118     @Override
onStop()119     public void onStop() {
120         super.onStop();
121     }
122 
123     /*
124      * Check if there is a global search intent
125      */
checkGlobalSearchIntent()126     private boolean checkGlobalSearchIntent() {
127         Intent intent = getActivity().getIntent();
128         String intentAction = intent.getAction();
129         String globalSearch = getString(R.string.global_search);
130         if (globalSearch.equalsIgnoreCase(intentAction)) {
131             Uri intentData = intent.getData();
132             Log.d(TAG, "action: " + intentAction + " intentData:" + intentData);
133             int selectedIndex = Integer.parseInt(intentData.getLastPathSegment());
134             HashMap<String, List<Movie>> movies = VideoProvider.getMovieList();
135             int movieTally = 0;
136             if (movies == null) {
137                 return false;
138             }
139             for (Map.Entry<String, List<Movie>> entry : movies.entrySet()) {
140                 List<Movie> list = entry.getValue();
141                 for (Movie movie : list) {
142                     movieTally++;
143                     if (selectedIndex == movieTally) {
144                         mSelectedMovie = movie;
145                         return true;
146                     }
147                 }
148             }
149         }
150         return false;
151     }
152 
prepareBackgroundManager()153     private void prepareBackgroundManager() {
154         mBackgroundManager = BackgroundManager.getInstance(getActivity());
155         mBackgroundManager.attach(getActivity().getWindow());
156         mDefaultBackground = getResources().getDrawable(R.drawable.default_background);
157         mMetrics = new DisplayMetrics();
158         getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
159     }
160 
updateBackground(String uri)161     protected void updateBackground(String uri) {
162         Glide.with(getActivity())
163                 .load(uri)
164                 .centerCrop()
165                 .error(mDefaultBackground)
166                 .into(new SimpleTarget<GlideDrawable>(mMetrics.widthPixels, mMetrics.heightPixels) {
167                     @Override
168                     public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
169                         mBackgroundManager.setDrawable(resource);
170                     }
171                 });
172     }
173 
setupAdapter()174     private void setupAdapter() {
175         mPresenterSelector = new ClassPresenterSelector();
176         mAdapter = new ArrayObjectAdapter(mPresenterSelector);
177         setAdapter(mAdapter);
178     }
179 
setupDetailsOverviewRow()180     private void setupDetailsOverviewRow() {
181         Log.d(TAG, "doInBackground: " + mSelectedMovie.toString());
182         final DetailsOverviewRow row = new DetailsOverviewRow(mSelectedMovie);
183         row.setImageDrawable(getResources().getDrawable(R.drawable.default_background));
184         int width = Utils.convertDpToPixel(getActivity()
185                 .getApplicationContext(), DETAIL_THUMB_WIDTH);
186         int height = Utils.convertDpToPixel(getActivity()
187                 .getApplicationContext(), DETAIL_THUMB_HEIGHT);
188         Glide.with(getActivity())
189                 .load(mSelectedMovie.getCardImageUrl())
190                 .centerCrop()
191                 .error(R.drawable.default_background)
192                 .into(new SimpleTarget<GlideDrawable>(width, height) {
193                     @Override
194                     public void onResourceReady(GlideDrawable resource,
195                                                 GlideAnimation<? super GlideDrawable>
196                                                         glideAnimation) {
197                         Log.d(TAG, "details overview card image url ready: " + resource);
198                         row.setImageDrawable(resource);
199                         mAdapter.notifyArrayItemRangeChanged(0, mAdapter.size());
200                     }
201                 });
202 
203         row.addAction(new Action(ACTION_WATCH_TRAILER, getResources().getString(
204                 R.string.watch_trailer_1), getResources().getString(R.string.watch_trailer_2)));
205         row.addAction(new Action(ACTION_RENT, getResources().getString(R.string.rent_1),
206                 getResources().getString(R.string.rent_2)));
207         row.addAction(new Action(ACTION_BUY, getResources().getString(R.string.buy_1),
208                 getResources().getString(R.string.buy_2)));
209 
210         mAdapter.add(row);
211     }
212 
setupDetailsOverviewRowPresenter()213     private void setupDetailsOverviewRowPresenter() {
214         // Set detail background and style.
215         DetailsOverviewRowPresenter detailsPresenter =
216                 new DetailsOverviewRowPresenter(new DetailsDescriptionPresenter());
217         detailsPresenter.setBackgroundColor(getResources().getColor(R.color.selected_background));
218         detailsPresenter.setStyleLarge(true);
219 
220         // Hook up transition element.
221         detailsPresenter.setSharedElementEnterTransition(getActivity(),
222                 MovieDetailsActivity.SHARED_ELEMENT_NAME);
223 
224         detailsPresenter.setOnActionClickedListener(new OnActionClickedListener() {
225             @Override
226             public void onActionClicked(Action action) {
227                 if (action.getId() == ACTION_WATCH_TRAILER) {
228                     Intent intent = new Intent(getActivity(), PlaybackOverlayActivity.class);
229                     intent.putExtra(MovieDetailsActivity.MOVIE, mSelectedMovie);
230                     startActivity(intent);
231                 } else {
232                     Toast.makeText(getActivity(), action.toString(), Toast.LENGTH_SHORT).show();
233                 }
234             }
235         });
236         mPresenterSelector.addClassPresenter(DetailsOverviewRow.class, detailsPresenter);
237     }
238 
setupMovieListRow()239     private void setupMovieListRow() {
240         String subcategories[] = {getString(R.string.related_movies)};
241         HashMap<String, List<Movie>> movies = VideoProvider.getMovieList();
242 
243         ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
244         for (Map.Entry<String, List<Movie>> entry : movies.entrySet()) {
245             if (mSelectedMovie.getCategory().indexOf(entry.getKey()) >= 0) {
246                 List<Movie> list = entry.getValue();
247                 for (int j = 0; j < list.size(); j++) {
248                     listRowAdapter.add(list.get(j));
249                 }
250             }
251         }
252         HeaderItem header = new HeaderItem(0, subcategories[0]);
253         mAdapter.add(new ListRow(header, listRowAdapter));
254     }
255 
setupMovieListRowPresenter()256     private void setupMovieListRowPresenter() {
257         mPresenterSelector.addClassPresenter(ListRow.class, new ListRowPresenter());
258     }
259 
260     private final class ItemViewClickedListener implements OnItemViewClickedListener {
261         @Override
onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row)262         public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
263                                   RowPresenter.ViewHolder rowViewHolder, Row row) {
264 
265             if (item instanceof Movie) {
266                 Movie movie = (Movie) item;
267                 Log.d(TAG, "Item: " + item.toString());
268                 Intent intent = new Intent(getActivity(), MovieDetailsActivity.class);
269                 intent.putExtra(MovieDetailsActivity.MOVIE, movie);
270 
271                 Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
272                         getActivity(),
273                         ((ImageCardView) itemViewHolder.view).getMainImageView(),
274                         MovieDetailsActivity.SHARED_ELEMENT_NAME).toBundle();
275                 getActivity().startActivity(intent, bundle);
276             }
277         }
278     }
279 }
280