/*
* Copyright (C) 2015 Fastboot Mobile, LLC.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, see <http://www.gnu.org/licenses>.
*/
package com.fastbootmobile.encore.app.tv;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.support.v17.leanback.app.BackgroundManager;
import android.support.v17.leanback.app.DetailsFragment;
import android.support.v17.leanback.widget.Action;
import android.support.v17.leanback.widget.ArrayObjectAdapter;
import android.support.v17.leanback.widget.ClassPresenterSelector;
import android.support.v17.leanback.widget.DetailsOverviewRow;
import android.support.v17.leanback.widget.DetailsOverviewRowPresenter;
import android.support.v17.leanback.widget.ListRow;
import android.support.v17.leanback.widget.ListRowPresenter;
import android.support.v17.leanback.widget.OnActionClickedListener;
import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import com.fastbootmobile.encore.app.R;
import com.fastbootmobile.encore.art.AlbumArtHelper;
import com.fastbootmobile.encore.art.RecyclingBitmapDrawable;
import com.fastbootmobile.encore.framework.PlaybackProxy;
import com.fastbootmobile.encore.framework.PluginsLookup;
import com.fastbootmobile.encore.model.Album;
import com.fastbootmobile.encore.model.Artist;
import com.fastbootmobile.encore.model.BoundEntity;
import com.fastbootmobile.encore.model.Playlist;
import com.fastbootmobile.encore.model.SearchResult;
import com.fastbootmobile.encore.model.Song;
import com.fastbootmobile.encore.providers.ILocalCallback;
import com.fastbootmobile.encore.providers.IMusicProvider;
import com.fastbootmobile.encore.providers.ProviderAggregator;
import com.fastbootmobile.encore.providers.ProviderConnection;
import com.fastbootmobile.encore.service.BasePlaybackCallback;
import com.fastbootmobile.encore.utils.Utils;
import java.util.Iterator;
import java.util.List;
public class TvAlbumDetailsFragment extends DetailsFragment {
private static final String TAG = "AlbumDetailsFragment";
private static final int DETAIL_THUMB_WIDTH = 274;
private static final int DETAIL_THUMB_HEIGHT = 274;
private static final int ACTION_PLAY = 1;
private static final int ACTION_QUEUE = 2;
private static final int ACTION_GO_TO_ARTIST = 3;
private static final int MSG_UPDATE_ADAPTER = 1;
private Album mAlbum;
private ArrayObjectAdapter mAdapter;
private ClassPresenterSelector mPresenterSelector;
private SongRowPresenter mSongRowPresenter;
private BackgroundManager mBackgroundManager;
private Drawable mDefaultBackground;
private int mBackgroundColor;
private DisplayMetrics mMetrics;
private Action mActionPlay;
private Action mActionQueue;
private Action mActionGoToArtist;
private boolean mIsPlaying;
private Handler mHandler;
private BasePlaybackCallback mPlaybackCallback;
private View.OnClickListener mSongClickListener;
private AlbumLocalCallback mCallback = new AlbumLocalCallback();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_ADAPTER:
updateAdapter();
break;
}
}
};
mPlaybackCallback = new BasePlaybackCallback() {
@Override
public void onSongStarted(boolean buffering, Song s) throws RemoteException {
mSongRowPresenter.setCurrentSong(PlaybackProxy.getCurrentTrack());
mHandler.sendEmptyMessage(MSG_UPDATE_ADAPTER);
}
};
mSongClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
SongRow row = (SongRow) v.getTag();
PlaybackProxy.clearQueue();
PlaybackProxy.queueAlbum(mAlbum, false);
PlaybackProxy.playAtIndex(row.getPosition());
mIsPlaying = true;
mActionPlay.setLabel1(getString(R.string.pause));
updateAdapter();
}
};
mActionPlay = new Action(ACTION_PLAY, getString(R.string.play));
mActionQueue = new Action(ACTION_QUEUE, getString(R.string.tv_action_queue));
mActionGoToArtist = new Action(ACTION_GO_TO_ARTIST, getString(R.string.menu_open_artist_page));
prepareBackgroundManager();
mAlbum = getActivity().getIntent().getParcelableExtra(TvAlbumDetailsActivity.EXTRA_ALBUM);
mAlbum = ProviderAggregator.getDefault().retrieveAlbum(mAlbum.getRef(), mAlbum.getProvider());
mBackgroundColor = getActivity().getIntent().getIntExtra(TvAlbumDetailsActivity.EXTRA_COLOR, getResources().getColor(R.color.primary));
if (mAlbum != null) {
setupAdapter();
setupDetailsOverviewRow();
setupDetailsOverviewRowPresenter();
setupTrackListRow();
setupTrackListRowPresenter();
setupFragmentBackground();
} else {
Intent intent = new Intent(getActivity(), TvActivity.class);
startActivity(intent);
}
}
@Override
public void onResume() {
super.onResume();
PlaybackProxy.addCallback(mPlaybackCallback);
ProviderAggregator.getDefault().addUpdateCallback(mCallback);
mSongRowPresenter.setCurrentSong(PlaybackProxy.getCurrentTrack());
updateAdapter();
}
@Override
public void onPause() {
super.onPause();
PlaybackProxy.removeCallback(mPlaybackCallback);
ProviderAggregator.getDefault().removeUpdateCallback(mCallback);
}
private void updateAdapter() {
mAdapter.notifyArrayItemRangeChanged(0, mAdapter.size());
}
private void prepareBackgroundManager() {
mBackgroundManager = BackgroundManager.getInstance(getActivity());
mBackgroundManager.attach(getActivity().getWindow());
mDefaultBackground = getResources().getDrawable(R.drawable.bg_welcome_top);
mMetrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
}
private void setupAdapter() {
mPresenterSelector = new ClassPresenterSelector();
mAdapter = new ArrayObjectAdapter(mPresenterSelector);
setAdapter(mAdapter);
ProviderConnection connection = PluginsLookup.getDefault().getProvider(mAlbum.getProvider());
if (connection != null) {
IMusicProvider binder = connection.getBinder();
if (binder != null) {
try {
binder.fetchAlbumTracks(mAlbum.getRef());
} catch (RemoteException e) {
Log.e(TAG, "Cannot request album tracks", e);
}
}
}
}
private void setupDetailsOverviewRow() {
final Resources res = getResources();
final DetailsOverviewRow row = new DetailsOverviewRow(mAlbum);
row.setImageDrawable(res.getDrawable(R.drawable.album_placeholder));
SparseArrayObjectAdapter actionsAdapter = new SparseArrayObjectAdapter();
actionsAdapter.set(ACTION_PLAY, mActionPlay);
actionsAdapter.set(ACTION_QUEUE, mActionQueue);
actionsAdapter.set(ACTION_GO_TO_ARTIST, mActionGoToArtist);
row.setActionsAdapter(actionsAdapter);
mAdapter.add(row);
AlbumArtHelper.retrieveAlbumArt(getResources(), new AlbumArtHelper.AlbumArtListener() {
@Override
public void onArtLoaded(RecyclingBitmapDrawable output, BoundEntity request) {
if (output != null) {
row.setImageDrawable(output);
updateAdapter();
}
}
}, mAlbum, DETAIL_THUMB_WIDTH, false);
}
private void setupDetailsOverviewRowPresenter() {
// Set detail background and style.
DetailsOverviewRowPresenter detailsPresenter =
new DetailsOverviewRowPresenter(new AlbumDetailsPresenter());
detailsPresenter.setBackgroundColor(mBackgroundColor);
detailsPresenter.setStyleLarge(false);
// Hook up transition element.
detailsPresenter.setSharedElementEnterTransition(getActivity(),
TvAlbumDetailsActivity.SHARED_ELEMENT_NAME);
detailsPresenter.setOnActionClickedListener(new OnActionClickedListener() {
@Override
public void onActionClicked(Action action) {
if (action.getId() == ACTION_PLAY) {
if (mIsPlaying) {
PlaybackProxy.pause();
mIsPlaying = false;
} else {
PlaybackProxy.playAlbum(mAlbum);
mIsPlaying = true;
}
mActionPlay.setLabel1(getString(mIsPlaying ? R.string.pause : R.string.play));
updateAdapter();
} else if (action.getId() == ACTION_QUEUE) {
PlaybackProxy.queueAlbum(mAlbum, false);
} else if (action.getId() == ACTION_GO_TO_ARTIST) {
String artistRef = Utils.getMainArtist(mAlbum);
if (artistRef != null) {
Artist artist = ProviderAggregator.getDefault().retrieveArtist(artistRef, mAlbum.getProvider());
final int color = getResources().getColor(R.color.primary);
Intent intent = new Intent(getActivity(), TvArtistDetailsActivity.class);
intent.putExtra(TvArtistDetailsActivity.EXTRA_ARTIST, artist);
intent.putExtra(TvArtistDetailsActivity.EXTRA_COLOR, color);
startActivity(intent);
}
}
}
});
mPresenterSelector.addClassPresenter(DetailsOverviewRow.class, detailsPresenter);
}
private void setupTrackListRow() {
mAdapter.removeItems(1, mAdapter.size() - 1);
Iterator<String> it = mAlbum.songs();
int index = 0;
while (it.hasNext()) {
String trackRef = it.next();
Song song = ProviderAggregator.getDefault().retrieveSong(trackRef, mAlbum.getProvider());
if (song != null) {
mAdapter.add(new SongRow(song, index++));
}
}
}
private void setupTrackListRowPresenter() {
mSongRowPresenter = new SongRowPresenter(mSongClickListener);
mPresenterSelector.addClassPresenter(ListRow.class, new ListRowPresenter());
mPresenterSelector.addClassPresenter(SongRow.class, mSongRowPresenter);
}
private void setupFragmentBackground() {
String artistRef = Utils.getMainArtist(mAlbum);
if (artistRef != null) {
Artist artist = ProviderAggregator.getDefault().retrieveArtist(artistRef, mAlbum.getProvider());
AlbumArtHelper.retrieveAlbumArt(getResources(), new AlbumArtHelper.AlbumArtListener() {
@Override
public void onArtLoaded(RecyclingBitmapDrawable output, BoundEntity request) {
if (output != null) {
mBackgroundManager.setDrawable(output);
}
}
}, artist, mMetrics.widthPixels, false);
}
}
private class AlbumLocalCallback implements ILocalCallback {
@Override
public void onSongUpdate(List<Song> s) {
mHandler.post(new Runnable() {
public void run() {
setupTrackListRow();
}
});
}
@Override
public void onAlbumUpdate(List<Album> a) {
mHandler.post(new Runnable() {
public void run() {
setupTrackListRow();
}
});
}
@Override
public void onPlaylistUpdate(List<Playlist> p) {
}
@Override
public void onPlaylistRemoved(String ref) {
}
@Override
public void onArtistUpdate(List<Artist> a) {
}
@Override
public void onProviderConnected(IMusicProvider provider) {
}
@Override
public void onSearchResult(List<SearchResult> searchResult) {
}
}
}