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