package de.danoeh.antennapodsp.fragment;
import android.app.Activity;
import android.content.Intent;
import android.content.res.TypedArray;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.PopupMenu;
import android.util.Log;
import android.util.TypedValue;
import android.view.*;
import android.view.View.OnClickListener;
import android.webkit.WebView;
import android.widget.*;
import de.danoeh.antennapodsp.AppConfig;
import de.danoeh.antennapodsp.R;
import de.danoeh.antennapodsp.activity.MainActivity;
import de.danoeh.antennapodsp.asynctask.ImageLoader;
import de.danoeh.antennapodsp.feed.Chapter;
import de.danoeh.antennapodsp.service.playback.PlaybackService;
import de.danoeh.antennapodsp.util.ChapterUtils;
import de.danoeh.antennapodsp.util.Converter;
import de.danoeh.antennapodsp.util.ShownotesProvider;
import de.danoeh.antennapodsp.util.playback.Playable;
import de.danoeh.antennapodsp.util.playback.PlaybackController;
import org.apache.commons.lang3.StringEscapeUtils;
import java.util.List;
import java.util.concurrent.Callable;
/**
* Fragment which is supposed to be displayed outside of the MediaplayerActivity
* if the PlaybackService is running
*/
public class ExternalPlayerFragment extends Fragment {
private static final String TAG = "ExternalPlayerFragment";
public static final String ARG_INITIAL_STATE = "argInitialState";
public static final int ARG_INIT_EPXANDED = 1;
public static final int ARG_INIT_ANCHORED = 0;
public static enum FragmentState {EXPANDED, ANCHORED}
// expanded layout components
private LinearLayout topviewExpanded;
private RelativeLayout layoutInfoExpanded;
private ImageView imgvCoverExpanded;
private TextView txtvTitleExpanded;
private ImageButton butActionExpanded;
private ImageButton butPlayExpanded;
private ImageButton butRevExpanded;
private ImageButton butFFExpanded;
private ImageButton butShowChapters;
private Button butSleep;
private TextView txtvPositionExpanded;
private TextView txtvLengthExpanded;
private WebView webvDescription;
private SeekBar sbPositionExanded;
private PopupMenu chaptersMenu;
// anchored layout components
private LinearLayout topViewAnchored;
private ImageView imgvCoverAnchored;
private ViewGroup layoutInfoAnchored;
private TextView txtvTitleAnchored;
private ImageButton butPlayAnchored;
private PlaybackController controller;
private FragmentState fragmentState;
public static ExternalPlayerFragment newInstance(int initialState) {
if (initialState != ARG_INIT_ANCHORED && initialState != ARG_INIT_EPXANDED)
throw new IllegalArgumentException("invalid initial state");
Bundle b = new Bundle();
b.putInt(ARG_INITIAL_STATE, initialState);
ExternalPlayerFragment f = new ExternalPlayerFragment();
f.setArguments(b);
return f;
}
public void setFragmentState(FragmentState fs) {
boolean stateChanged = fs != fragmentState;
fragmentState = fs;
if (topViewAnchored != null && topviewExpanded != null) {
if (fs == FragmentState.ANCHORED) {
topviewExpanded.setVisibility(View.GONE);
topViewAnchored.setVisibility(View.VISIBLE);
} else {
topViewAnchored.setVisibility(View.GONE);
topviewExpanded.setVisibility(View.VISIBLE);
}
}
if (stateChanged && controller != null) {
controller.repeatHandleStatus();
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int state = getArguments().getInt(ARG_INITIAL_STATE);
if (state == ARG_INIT_ANCHORED) {
fragmentState = FragmentState.ANCHORED;
} else if (state == ARG_INIT_EPXANDED) {
fragmentState = FragmentState.EXPANDED;
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.external_player_fragment,
container, false);
// Expanded components
topviewExpanded = (LinearLayout) root.findViewById(R.id.topviewExpanded);
imgvCoverExpanded = (ImageView) root.findViewById(R.id.imgvCoverExpanded);
txtvTitleExpanded = (TextView) root.findViewById(R.id.txtvTitleExpanded);
butActionExpanded = (ImageButton) root.findViewById(R.id.butActionExpanded);
butPlayExpanded = (ImageButton) root.findViewById(R.id.butPlayExpanded);
butRevExpanded = (ImageButton) root.findViewById(R.id.butRevExpanded);
butFFExpanded = (ImageButton) root.findViewById(R.id.butFFExpanded);
butShowChapters = (ImageButton) root.findViewById(R.id.butShowChapters);
butSleep = (Button) root.findViewById(R.id.butSleep);
txtvPositionExpanded = (TextView) root.findViewById(R.id.txtvPositionExpanded);
txtvLengthExpanded = (TextView) root.findViewById(R.id.txtvLengthExpanded);
sbPositionExanded = (SeekBar) root.findViewById(R.id.sbPositionExpanded);
webvDescription = (WebView) root.findViewById(R.id.webvDescription);
layoutInfoExpanded = (RelativeLayout) root.findViewById(R.id.layoutInfo_expanded);
chaptersMenu = new PopupMenu(container.getContext(), butShowChapters);
// Anchored components
topViewAnchored = (LinearLayout) root.findViewById(R.id.topviewAnchored);
imgvCoverAnchored = (ImageView) root.findViewById(R.id.imgvCoverAnchored);
layoutInfoAnchored = (ViewGroup) root.findViewById(R.id.layoutInfo_anchored);
txtvTitleAnchored = (TextView) root.findViewById(R.id.txtvTitleAnchored);
butPlayAnchored = (ImageButton) root.findViewById(R.id.butPlayAnchored);
layoutInfoAnchored.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (AppConfig.DEBUG)
Log.d(TAG, "layoutInfo was clicked");
if (controller.getMedia() != null) {
startActivity(PlaybackService.getPlayerActivityIntent(
getActivity(), controller.getMedia()));
}
}
});
butShowChapters.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
setupChaptersMenu();
chaptersMenu.show();
}
});
chaptersMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
if (controller == null) {
return true;
}
Playable p = controller.getMedia();
if (p == null) {
return true;
}
List<Chapter> chs = p.getChapters();
if (chs == null) {
return true;
}
final int id = menuItem.getItemId();
if (id >= 0 && id < chs.size()) {
controller.seekToChapter(chs.get(id));
}
return true;
}
});
((MainActivity) getActivity()).onPlayerFragmentCreated(this, fragmentState);
return root;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
controller = setupPlaybackController();
butPlayExpanded.setOnClickListener(controller.newOnPlayButtonClickListener());
butPlayAnchored.setOnClickListener(controller.newOnPlayButtonClickListener());
sbPositionExanded.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
float prog = 0;
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
prog = controller.onSeekBarProgressChanged(seekBar, progress, fromUser, txtvPositionExpanded);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
controller.onSeekBarStartTrackingTouch(seekBar);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
controller.onSeekBarStopTrackingTouch(seekBar, prog);
prog = 0;
}
});
butRevExpanded.setOnClickListener(controller.newOnRevButtonClickListener());
butFFExpanded.setOnClickListener(controller.newOnFFButtonClickListener());
butSleep.setOnClickListener(controller.newOnSleepButtonClickListener());
butActionExpanded.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Playable media;
if (controller != null && (media = controller.getMedia()) != null && media.getWebsiteLink() != null) {
Uri uri = Uri.parse(media.getWebsiteLink());
startActivity(new Intent(Intent.ACTION_VIEW, uri));
}
}
});
setFragmentState(fragmentState);
}
public void setButSleepText(String text) {
butSleep.setText(text);
}
private void updateTimeDisplay() {
int duration = controller.getDuration();
int position = controller.getPosition();
if (duration != PlaybackController.INVALID_TIME
&& position != PlaybackController.INVALID_TIME) {
txtvPositionExpanded.setText(Converter.getDurationStringLong(position));
txtvLengthExpanded.setText(Converter.getDurationStringLong(duration));
setProgressBarProgress(position, duration);
}
if (controller.sleepTimerActive()) {
int sleepLeft = (int) controller.getSleepTimerTimeLeft();
butSleep.setText(Converter.getDurationStringLong(sleepLeft));
} else {
butSleep.setText("");
}
}
private PlaybackController setupPlaybackController() {
return new PlaybackController(getActivity(), true) {
@Override
public void setupGUI() {
}
@Override
public void onPositionObserverUpdate() {
updateTimeDisplay();
}
@Override
public void onReloadNotification(int code) {
}
@Override
public void onBufferStart() {
// TODO Auto-generated method stub
}
@Override
public void onBufferEnd() {
// TODO Auto-generated method stub
}
@Override
public void onBufferUpdate(float progress) {
}
@Override
public void onSleepTimerUpdate() {
}
@Override
public void handleError(int code) {
}
@Override
public ImageButton getPlayButton() {
if (fragmentState == FragmentState.EXPANDED)
return butPlayExpanded;
else
return butPlayAnchored;
}
@Override
public void postStatusMsg(int msg) {
}
@Override
public void clearStatusMsg() {
}
@Override
public boolean loadMediaInfo() {
ExternalPlayerFragment fragment = ExternalPlayerFragment.this;
if (fragment != null) {
return fragment.loadMediaInfo();
} else {
return false;
}
}
@Override
public void onAwaitingVideoSurface() {
}
@Override
public void onServiceQueried() {
}
@Override
public void onShutdownNotification() {
((MainActivity) getActivity()).resetPlayer();
setFragmentState(FragmentState.ANCHORED);
resetLayout();
}
@Override
public void onPlaybackEnd() {
((MainActivity) getActivity()).resetPlayer();
setFragmentState(FragmentState.ANCHORED);
resetLayout();
}
@Override
public void onPlaybackSpeedChange() {
// TODO Auto-generated method stub
}
};
}
@Override
public void onResume() {
super.onResume();
controller.init();
}
@Override
public void onDestroy() {
super.onDestroy();
if (AppConfig.DEBUG)
Log.d(TAG, "Fragment is about to be destroyed");
if (controller != null) {
controller.release();
}
}
@Override
public void onPause() {
super.onPause();
if (controller != null) {
controller.pause();
}
}
private boolean loadMediaInfo() {
if (AppConfig.DEBUG)
Log.d(TAG, "Loading media info");
if (controller.serviceAvailable()) {
Playable media = controller.getMedia();
if (media != null) {
txtvTitleExpanded.setText(media.getEpisodeTitle());
txtvTitleAnchored.setText(media.getEpisodeTitle());
ImageLoader.getInstance().loadThumbnailBitmap(
media,
imgvCoverExpanded,
(int) getActivity().getResources().getDimension(
R.dimen.external_player_height)
);
ImageLoader.getInstance().loadThumbnailBitmap(
media,
imgvCoverAnchored,
(int) getActivity().getResources().getDimension(
R.dimen.external_player_height)
);
txtvPositionExpanded.setText(Converter.getDurationStringLong(media.getPosition()));
txtvLengthExpanded.setText(Converter.getDurationStringLong(media.getDuration()));
if (controller.sleepTimerActive()) {
butSleep.setText(Converter.getDurationStringLong((int) controller.getSleepTimerTimeLeft()));
} else {
butSleep.setText("");
}
loadDescriptionWebview(media);
if (media.getWebsiteLink() == null) {
butActionExpanded.setVisibility(View.INVISIBLE);
} else {
butActionExpanded.setVisibility(View.VISIBLE);
}
setProgressBarProgress(media.getPosition(), media.getDuration());
if (media.getChapters() != null) {
butShowChapters.setVisibility(View.VISIBLE);
setupChaptersMenu();
} else {
butShowChapters.setVisibility(View.INVISIBLE);
}
/*
if (controller.isPlayingVideo()) {
butPlay.setVisibility(View.GONE);
} else {
butPlay.setVisibility(View.VISIBLE);
}
*/
((MainActivity) getActivity()).openPlayer(fragmentState);
return true;
} else {
Log.w(TAG,
"loadMediaInfo was called while the media object of playbackService was null!");
return false;
}
} else {
Log.w(TAG,
"loadMediaInfo was called while playbackService was null!");
return false;
}
}
public View getExpandView() {
return layoutInfoAnchored;
}
public View getCollapseView() {
return layoutInfoExpanded;
}
private void setProgressBarProgress(int position, int duration) {
float progress = ((float) position) / duration;
sbPositionExanded.setProgress((int) (progress * sbPositionExanded.getMax()));
}
private void resetLayout() {
imgvCoverExpanded.setImageBitmap(null);
imgvCoverAnchored.setImageBitmap(null);
txtvTitleExpanded.setText(getString(R.string.no_media_playing_label));
txtvTitleAnchored.setText(getString(R.string.no_media_playing_label));
txtvPositionExpanded.setText("");
txtvLengthExpanded.setText("");
butSleep.setText("");
webvDescription.clearView();
}
/**
* Creates the content of the chapter menu.
*
* @return true if a menu was created, false otherwise
*/
private boolean setupChaptersMenu() {
if (chaptersMenu == null || controller == null) {
Log.e(TAG, "setupChaptersMenu was called while chaptersMenu or controller was null");
return false;
}
chaptersMenu.getMenu().clear();
Playable p = controller.getMedia();
if (p == null || p.getChapters() == null) {
return false;
}
Menu menu = chaptersMenu.getMenu();
final String currentChapterPrefix = "\u25B6 ";
final Chapter currentChapter = ChapterUtils.getCurrentChapter(p);
for (int i = 0; i < p.getChapters().size(); i++) {
Chapter ch = p.getChapters().get(i);
String menuText = ((ch == currentChapter) ? currentChapterPrefix : "") + ch.getTitle();
menu.add(Menu.NONE, i, Menu.NONE, menuText);
}
return true;
}
private void loadDescriptionWebview(final ShownotesProvider shownotesProvider) {
AsyncTask<Void, Void, Void> loadTask = new AsyncTask<Void, Void, Void>() {
String data;
private String applyWebviewStyle(String textColor, String data) {
final String WEBVIEW_STYLE = "<html><head><style type=\"text/css\"> * { color: %s; font-family: Helvetica; line-height: 1.3em; font-size: 11pt; } a { font-style: normal; text-decoration: none; font-weight: normal; color: #00A8DF; } img { display: block; margin: 10 auto; max-width: %s; height: auto; } body { margin: %dpx %dpx %dpx %dpx; }</style></head><body>%s</body></html>";
final int pageMargin = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 8, getResources()
.getDisplayMetrics()
);
return String.format(WEBVIEW_STYLE, textColor, "100%", pageMargin,
pageMargin, pageMargin, pageMargin, data);
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// /webvDescription.loadData(url, "text/html", "utf-8");
if (ExternalPlayerFragment.this.isAdded() && webvDescription != null) {
webvDescription.loadDataWithBaseURL(null, data, "text/html",
"utf-8", "about:blank");
if (getActivity() != null) {
((ActionBarActivity) getActivity())
.setSupportProgressBarIndeterminateVisibility(false);
}
if (AppConfig.DEBUG)
Log.d(TAG, "Webview loaded");
}
}
@Override
protected void onPreExecute() {
super.onPreExecute();
if (getActivity() != null) {
((ActionBarActivity) getActivity())
.setSupportProgressBarIndeterminateVisibility(false);
}
}
@Override
protected Void doInBackground(Void... params) {
if (AppConfig.DEBUG)
Log.d(TAG, "Loading Webview");
try {
Callable<String> shownotesLoadTask = shownotesProvider.loadShownotes();
final String shownotes = shownotesLoadTask.call();
data = StringEscapeUtils.unescapeHtml4(shownotes);
Activity activity = getActivity();
if (activity != null) {
TypedArray res = activity
.getTheme()
.obtainStyledAttributes(
new int[]{android.R.attr.textColorPrimary});
int colorResource = res.getColor(0, 0);
String colorString = String.format("#%06X",
0xFFFFFF & colorResource);
Log.i(TAG, "text color: " + colorString);
res.recycle();
data = applyWebviewStyle(colorString, data);
} else {
cancel(true);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
};
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
loadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
loadTask.execute();
}
}
}