1 /* 2 * Copyright (C) 2015 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 android.support.v17.leanback.supportleanbackshowcase.app.media; 16 17 import android.content.Context; 18 import android.content.res.Resources; 19 import android.graphics.drawable.Drawable; 20 import android.net.Uri; 21 import android.os.Bundle; 22 import android.support.v17.leanback.app.PlaybackOverlayFragment; 23 import android.support.v17.leanback.supportleanbackshowcase.utils.Constants; 24 import android.support.v17.leanback.supportleanbackshowcase.R; 25 import android.support.v17.leanback.supportleanbackshowcase.utils.Utils; 26 import android.support.v17.leanback.supportleanbackshowcase.models.Song; 27 import android.support.v17.leanback.supportleanbackshowcase.models.SongList; 28 import android.support.v17.leanback.widget.*; 29 import android.support.v17.leanback.widget.AbstractMediaItemPresenter; 30 import android.util.Log; 31 32 import com.google.gson.Gson; 33 34 import java.util.List; 35 36 /** 37 * This example shows how to play music files and build a simple track list. 38 */ 39 public class MusicConsumptionExampleFragment extends PlaybackOverlayFragment implements 40 BaseOnItemViewClickedListener, BaseOnItemViewSelectedListener, 41 MediaPlayerGlue.OnMediaFileFinishedPlayingListener { 42 43 private static final String TAG = "MusicConsumptionExampleFragment"; 44 private static final int PLAYLIST_ACTION_ID = 0; 45 private static final int FAVORITE_ACTION_ID = 1; 46 private ArrayObjectAdapter mRowsAdapter; 47 private MediaPlayerGlue mGlue; 48 private int mCurrentSongIndex = 0; 49 private List<Song> mSongList; 50 private boolean mAdapterNotified = false; 51 52 @Override public void onCreate(Bundle savedInstanceState) { 53 super.onCreate(savedInstanceState); 54 if (Constants.LOCAL_LOGD) Log.d(TAG, "onCreate"); 55 56 mGlue = new MediaPlayerGlue(getActivity(), this) { 57 58 @Override protected void onRowChanged(PlaybackControlsRow row) { 59 if (mRowsAdapter == null || mAdapterNotified) return; 60 //mAdapterNotified = true; 61 mRowsAdapter.notifyArrayItemRangeChanged(0, 1); 62 } 63 }; 64 mGlue.setOnMediaFileFinishedPlayingListener(this); 65 66 String json = Utils.inputStreamToString( 67 getResources().openRawResource(R.raw.music_consumption_example)); 68 69 70 mSongList = new Gson().fromJson(json, SongList.class).getSongs(); 71 72 Resources res = getActivity().getResources(); 73 74 // For each song add a playlist and favorite actions. 75 for(Song song : mSongList) { 76 MultiActionsProvider.MultiAction[] mediaRowActions = new 77 MultiActionsProvider.MultiAction[2]; 78 MultiActionsProvider.MultiAction playlistAction = new 79 MultiActionsProvider.MultiAction(PLAYLIST_ACTION_ID); 80 Drawable[] playlistActionDrawables = new Drawable[] { 81 res.getDrawable(R.drawable.ic_playlist_add_white_24dp, 82 getActivity().getTheme()), 83 res.getDrawable(R.drawable.ic_playlist_add_filled_24dp, 84 getActivity().getTheme())}; 85 playlistAction.setDrawables(playlistActionDrawables); 86 mediaRowActions[0] = playlistAction; 87 88 MultiActionsProvider.MultiAction favoriteAction = new 89 MultiActionsProvider.MultiAction(FAVORITE_ACTION_ID); 90 Drawable[] favoriteActionDrawables = new Drawable[] { 91 res.getDrawable(R.drawable.ic_favorite_border_white_24dp, 92 getActivity().getTheme()), 93 res.getDrawable(R.drawable.ic_favorite_filled_24dp, 94 getActivity().getTheme())}; 95 favoriteAction.setDrawables(favoriteActionDrawables); 96 mediaRowActions[1] = favoriteAction; 97 song.setMediaRowActions(mediaRowActions); 98 } 99 100 Song song = mSongList.get(mCurrentSongIndex); 101 MediaPlayerGlue.MetaData metaData = new MediaPlayerGlue.MetaData(); 102 metaData.setArtist(song.getDescription()); 103 metaData.setTitle(song.getTitle()); 104 metaData.setCover(getResources().getDrawable(song.getImageResource(getActivity()), null)); 105 Uri uri = Utils.getResourceUri(getActivity(), song.getFileResource(getActivity())); 106 mGlue.setMetaData(metaData); 107 mGlue.setMediaSource(uri); 108 mGlue.prepareMediaForPlaying(); 109 110 addPlaybackControlsRow(); 111 } 112 113 @Override public void onStart() { 114 super.onStart(); 115 mGlue.enableProgressUpdating(mGlue.hasValidMedia() && mGlue.isMediaPlaying()); 116 } 117 118 @Override public void onStop() { 119 super.onStop(); 120 mGlue.enableProgressUpdating(false); 121 mGlue.reset(); 122 } 123 124 static class SongPresenter extends AbstractMediaItemPresenter { 125 126 SongPresenter() { 127 super(); 128 } 129 130 SongPresenter(Context context, int themeResId) { 131 super(themeResId); 132 setHasMediaRowSeparator(true); 133 } 134 135 @Override 136 protected void onBindMediaDetails(ViewHolder vh, Object item) { 137 138 int favoriteTextColor = vh.view.getContext().getResources().getColor( 139 R.color.song_row_favorite_color); 140 Song song = (Song) item; 141 vh.getMediaItemNumberView().setText("" + song.getNumber()); 142 143 String songTitle = song.getTitle() + " / " + song.getDescription(); 144 vh.getMediaItemNameView().setText(songTitle); 145 146 vh.getMediaItemDurationView().setText("" + song.getDuration()); 147 148 if (song.isFavorite()) { 149 vh.getMediaItemNumberView().setTextColor(favoriteTextColor); 150 vh.getMediaItemNameView().setTextColor(favoriteTextColor); 151 vh.getMediaItemDurationView().setTextColor(favoriteTextColor); 152 } else { 153 Context context = vh.getMediaItemNumberView().getContext(); 154 vh.getMediaItemNumberView().setTextAppearance(context, 155 R.style.TextAppearance_Leanback_PlaybackMediaItemNumber); 156 vh.getMediaItemNameView().setTextAppearance(context, 157 R.style.TextAppearance_Leanback_PlaybackMediaItemName); 158 vh.getMediaItemDurationView().setTextAppearance(context, 159 R.style.TextAppearance_Leanback_PlaybackMediaItemDuration); 160 } 161 } 162 }; 163 164 static class SongPresenterSelector extends PresenterSelector { 165 Presenter mRegularPresenter; 166 Presenter mFavoritePresenter; 167 168 /** 169 * Adds a presenter to be used for the given class. 170 */ 171 public SongPresenterSelector setSongPresenterRegular(Presenter presenter) { 172 mRegularPresenter = presenter; 173 return this; 174 } 175 176 /** 177 * Adds a presenter to be used for the given class. 178 */ 179 public SongPresenterSelector setSongPresenterFavorite(Presenter presenter) { 180 mFavoritePresenter = presenter; 181 return this; 182 } 183 184 @Override 185 public Presenter[] getPresenters() { 186 return new Presenter[]{mRegularPresenter, mFavoritePresenter}; 187 } 188 189 @Override 190 public Presenter getPresenter(Object item) { 191 return ( (Song) item).isFavorite() ? mFavoritePresenter : mRegularPresenter; 192 } 193 194 } 195 196 static class TrackListHeaderPresenter extends AbstractMediaListHeaderPresenter { 197 198 TrackListHeaderPresenter() { 199 super(); 200 } 201 202 @Override 203 protected void onBindMediaListHeaderViewHolder(ViewHolder vh, Object item) { 204 vh.getHeaderView().setText("Tracklist"); 205 } 206 }; 207 208 private void addPlaybackControlsRow() { 209 mRowsAdapter = new ArrayObjectAdapter(new ClassPresenterSelector() 210 .addClassPresenterSelector(Song.class, new SongPresenterSelector() 211 .setSongPresenterRegular(new SongPresenter(getActivity(), 212 R.style.Theme_Example_LeanbackMusic_RegularSongNumbers)) 213 .setSongPresenterFavorite(new SongPresenter(getActivity(), 214 R.style.Theme_Example_LeanbackMusic_FavoriteSongNumbers))) 215 .addClassPresenter(TrackListHeader.class, new TrackListHeaderPresenter()) 216 .addClassPresenter(PlaybackControlsRow.class, 217 mGlue.createControlsRowAndPresenter())); 218 mRowsAdapter.add(mGlue.getControlsRow()); 219 mRowsAdapter.add(new TrackListHeader()); 220 mRowsAdapter.addAll(2, mSongList); 221 setAdapter(mRowsAdapter); 222 setOnItemViewClickedListener(this); 223 setOnItemViewSelectedListener(this); 224 } 225 226 public MusicConsumptionExampleFragment() { 227 super(); 228 } 229 230 231 232 @Override public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, 233 RowPresenter.ViewHolder rowViewHolder, Object row) { 234 235 if (item instanceof Action) { 236 // if the clicked item is a primary or secondary action in the playback controller 237 mGlue.onActionClicked((Action) item); 238 } else if (row instanceof Song) { 239 // if a media item row is clicked 240 Song clickedSong = (Song) row; 241 AbstractMediaItemPresenter.ViewHolder songRowVh = 242 (AbstractMediaItemPresenter.ViewHolder) rowViewHolder; 243 244 // if an action within a media item row is clicked 245 if (item instanceof MultiActionsProvider.MultiAction) { 246 if ( ((MultiActionsProvider.MultiAction) item).getId() == FAVORITE_ACTION_ID) { 247 MultiActionsProvider.MultiAction favoriteAction = 248 (MultiActionsProvider.MultiAction) item; 249 MultiActionsProvider.MultiAction playlistAction = 250 songRowVh.getMediaItemRowActions()[0]; 251 favoriteAction.incrementIndex(); 252 playlistAction.incrementIndex();; 253 254 clickedSong.setFavorite(!clickedSong.isFavorite()); 255 songRowVh.notifyDetailsChanged(); 256 songRowVh.notifyActionChanged(playlistAction); 257 songRowVh.notifyActionChanged(favoriteAction); 258 } 259 } else if (item == null){ 260 // if a media item details is clicked, start playing that media item 261 onSongDetailsClicked(clickedSong); 262 } 263 264 } 265 266 267 } 268 269 @Override 270 public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item, 271 RowPresenter.ViewHolder rowViewHolder, Object row) { 272 } 273 274 275 public void onSongDetailsClicked(Song song) { 276 int nextSongIndex = mSongList.indexOf(song); 277 mCurrentSongIndex = nextSongIndex; 278 startPlayback(); 279 } 280 281 282 @Override public void onMediaFileFinishedPlaying(MediaPlayerGlue.MetaData song) { 283 if (mGlue.repeatOne()) { 284 } else if (mGlue.useShuffle()) { 285 mCurrentSongIndex = (int) (Math.random() * mSongList.size()); 286 } else { 287 mCurrentSongIndex++; 288 if (mCurrentSongIndex >= mSongList.size()) { 289 mCurrentSongIndex = 0; 290 if (!mGlue.repeatAll()) { 291 return; 292 } 293 } 294 } 295 startPlayback(); 296 } 297 298 private void startPlayback() { 299 Song song = mSongList.get(mCurrentSongIndex); 300 MediaPlayerGlue.MetaData metaData = new MediaPlayerGlue.MetaData(); 301 metaData.setArtist(song.getDescription()); 302 metaData.setTitle(song.getTitle()); 303 metaData.setCover(getResources().getDrawable(song.getImageResource(getActivity()), null)); 304 305 Uri uri = Utils.getResourceUri(getActivity(), song.getFileResource(getActivity())); 306 mGlue.setMetaData(metaData); 307 308 if (mGlue.setMediaSource(uri)) { 309 mGlue.prepareMediaForPlaying(); 310 } 311 mGlue.startPlayback(); 312 } 313 } 314