Home | History | Annotate | Download | only in ui
      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
     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 
    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
    119     public void onStop() {
    120         super.onStop();
    121     }
    122 
    123     /*
    124      * Check if there is a global search intent
    125      */
    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 
    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 
    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 
    174     private void setupAdapter() {
    175         mPresenterSelector = new ClassPresenterSelector();
    176         mAdapter = new ArrayObjectAdapter(mPresenterSelector);
    177         setAdapter(mAdapter);
    178     }
    179 
    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 
    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 
    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 
    256     private void setupMovieListRowPresenter() {
    257         mPresenterSelector.addClassPresenter(ListRow.class, new ListRowPresenter());
    258     }
    259 
    260     private final class ItemViewClickedListener implements OnItemViewClickedListener {
    261         @Override
    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