summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordaniel oeh <daniel.oeh@gmail.com>2012-09-06 14:48:14 +0200
committerdaniel oeh <daniel.oeh@gmail.com>2012-09-06 14:48:14 +0200
commite2e26d9f485260544210be4bb349c4a9bd1ec575 (patch)
tree6b5791af8f81ce58a8a128a948db964d365f779b
parent2e9bd1f07e35dd08358f5f7d2ff7a8fef462a79f (diff)
downloadAntennaPod-e2e26d9f485260544210be4bb349c4a9bd1ec575.zip
Implemented PlaybackController in the MediaPlayerActivities
-rw-r--r--src/de/danoeh/antennapod/activity/AudioplayerActivity.java21
-rw-r--r--src/de/danoeh/antennapod/activity/MediaplayerActivity.java563
-rw-r--r--src/de/danoeh/antennapod/activity/VideoplayerActivity.java23
-rw-r--r--src/de/danoeh/antennapod/util/PlaybackController.java565
4 files changed, 722 insertions, 450 deletions
diff --git a/src/de/danoeh/antennapod/activity/AudioplayerActivity.java b/src/de/danoeh/antennapod/activity/AudioplayerActivity.java
index 3e9eed1ef..3587775a5 100644
--- a/src/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/src/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -17,6 +17,7 @@ import com.viewpagerindicator.TabPageIndicator;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.SCListAdapter;
+import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.feed.SimpleChapter;
import de.danoeh.antennapod.fragment.CoverFragment;
import de.danoeh.antennapod.fragment.ItemDescriptionFragment;
@@ -58,6 +59,8 @@ public class AudioplayerActivity extends MediaplayerActivity {
viewpager = (ViewPager) findViewById(R.id.viewpager);
tabs = (TabPageIndicator) findViewById(R.id.tabs);
+ FeedMedia media = controller.getMedia();
+
int tabcount = 2;
if (media != null && media.getItem().getSimpleChapters() != null) {
tabcount = 3;
@@ -77,13 +80,12 @@ public class AudioplayerActivity extends MediaplayerActivity {
@Override
protected void loadMediaInfo() {
super.loadMediaInfo();
- if (!mediaInfoLoaded && media != null) {
+ if (controller.getMedia() != null) {
pagerAdapter.notifyDataSetChanged();
-
}
}
- public static class MediaPlayerPagerAdapter extends
+ public class MediaPlayerPagerAdapter extends
FragmentStatePagerAdapter {
private int numItems;
private AudioplayerActivity activity;
@@ -103,15 +105,16 @@ public class AudioplayerActivity extends MediaplayerActivity {
@Override
public Fragment getItem(int position) {
- if (activity.media != null) {
+ FeedMedia media = controller.getMedia();
+ if (media != null) {
switch (position) {
case POS_COVER:
activity.coverFragment = CoverFragment
- .newInstance(activity.media.getItem());
+ .newInstance(media.getItem());
return activity.coverFragment;
case POS_DESCR:
activity.descriptionFragment = ItemDescriptionFragment
- .newInstance(activity.media.getItem());
+ .newInstance(media.getItem());
return activity.descriptionFragment;
case POS_CHAPTERS:
sCChapterFragment = new SherlockListFragment() {
@@ -122,15 +125,13 @@ public class AudioplayerActivity extends MediaplayerActivity {
super.onListItemClick(l, v, position, id);
SimpleChapter chapter = (SimpleChapter) this
.getListAdapter().getItem(position);
- if (activity.playbackService != null) {
- activity.playbackService.seekToChapter(chapter);
- }
+ controller.seekToChapter(chapter);
}
};
sCChapterFragment.setListAdapter(new SCListAdapter(
- activity, 0, activity.media.getItem()
+ activity, 0, media.getItem()
.getSimpleChapters()));
return sCChapterFragment;
diff --git a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java
index 771450cbf..6d56861e9 100644
--- a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -1,28 +1,16 @@
package de.danoeh.antennapod.activity;
-import android.annotation.SuppressLint;
import android.app.AlertDialog;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
-import android.media.MediaPlayer;
-import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.IBinder;
import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.SeekBar;
-import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
+import android.widget.SeekBar.OnSeekBarChangeListener;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
@@ -30,15 +18,13 @@ import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.dialog.TimeDialog;
import de.danoeh.antennapod.feed.FeedManager;
import de.danoeh.antennapod.feed.FeedMedia;
-import de.danoeh.antennapod.service.PlaybackService;
-import de.danoeh.antennapod.service.PlayerStatus;
import de.danoeh.antennapod.util.Converter;
import de.danoeh.antennapod.util.MediaPlayerError;
+import de.danoeh.antennapod.util.PlaybackController;
import de.danoeh.antennapod.util.StorageUtils;
import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler;
@@ -50,16 +36,10 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
implements OnSeekBarChangeListener {
private static final String TAG = "MediaplayerActivity";
- static final int DEFAULT_SEEK_DELTA = 30000;
-
- /** True if media information was loaded. */
- protected boolean mediaInfoLoaded = false;
- protected PlaybackService playbackService;
- protected MediaPositionObserver positionObserver;
- protected FeedMedia media;
- protected PlayerStatus status;
protected FeedManager manager;
+ protected PlaybackController controller;
+
protected TextView txtvPosition;
protected TextView txtvLength;
protected SeekBar sbPosition;
@@ -67,6 +47,86 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
protected ImageButton butRev;
protected ImageButton butFF;
+ public MediaplayerActivity() {
+ super();
+ controller = new PlaybackController(this) {
+
+ @Override
+ public void setupGUI() {
+ MediaplayerActivity.this.setupGUI();
+ }
+
+ @Override
+ public void onPositionObserverUpdate() {
+ MediaplayerActivity.this.onPositionObserverUpdate();
+ }
+
+ @Override
+ public void onBufferStart() {
+ MediaplayerActivity.this.onBufferStart();
+ }
+
+ @Override
+ public void onBufferEnd() {
+ MediaplayerActivity.this.onBufferEnd();
+ }
+
+ @Override
+ public void onBufferUpdate(float progress) {
+ MediaplayerActivity.this.onBufferUpdate(progress);
+ }
+
+ @Override
+ public void handleError(int code) {
+ MediaplayerActivity.this.handleError(code);
+ }
+
+ @Override
+ public void onReloadNotification(int code) {
+ MediaplayerActivity.this.onReloadNotification(code);
+ }
+
+ @Override
+ public void onSleepTimerUpdate() {
+ invalidateOptionsMenu();
+ }
+
+ @Override
+ public ImageButton getPlayButton() {
+ return butPlay;
+ }
+
+ @Override
+ public void postStatusMsg(int msg) {
+ MediaplayerActivity.this.postStatusMsg(msg);
+ }
+
+ @Override
+ public void clearStatusMsg() {
+ MediaplayerActivity.this.clearStatusMsg();
+ }
+
+ @Override
+ public void loadMediaInfo() {
+ MediaplayerActivity.this.loadMediaInfo();
+ }
+
+ @Override
+ public void onAwaitingVideoSurface() {
+ MediaplayerActivity.this.onAwaitingVideoSurface();
+ }
+
+ @Override
+ public void onServiceQueried() {
+ MediaplayerActivity.this.onServiceQueried();
+ }
+ };
+ }
+
+ protected void onServiceQueried() {
+ invalidateOptionsMenu();
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -78,77 +138,14 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
manager = FeedManager.getInstance();
getWindow().setFormat(PixelFormat.TRANSPARENT);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- bindToService();
}
@Override
protected void onPause() {
super.onPause();
- mediaInfoLoaded = false;
+ controller.pause();
}
- protected OnClickListener playbuttonListener = new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (playbackService != null) {
- switch (status) {
- case PLAYING:
- playbackService.pause(true);
- break;
- case PAUSED:
- case PREPARED:
- playbackService.play();
- break;
- case PREPARING:
- playbackService.setStartWhenPrepared(!playbackService
- .isStartWhenPrepared());
- }
- } else {
- Log.w(TAG,
- "Play/Pause button was pressed, but playbackservice was null!");
- }
- }
-
- };
- protected ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- playbackService = ((PlaybackService.LocalBinder) service)
- .getService();
-
- registerReceiver(statusUpdate, new IntentFilter(
- PlaybackService.ACTION_PLAYER_STATUS_CHANGED));
-
- registerReceiver(notificationReceiver, new IntentFilter(
- PlaybackService.ACTION_PLAYER_NOTIFICATION));
-
- queryService();
- if (AppConfig.DEBUG)
- Log.d(TAG, "Connection to Service established");
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- playbackService = null;
- if (AppConfig.DEBUG)
- Log.d(TAG, "Disconnected from Service");
-
- }
- };
- protected BroadcastReceiver statusUpdate = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Received statusUpdate Intent.");
- if (playbackService != null) {
- status = playbackService.getStatus();
- handleStatus();
- } else {
- Log.w(TAG,
- "Couldn't receive status update: playbackService was null");
- }
- }
- };
-
/**
* Should be used to switch to another player activity if the mime type is
* not the correct one for the current activity.
@@ -166,56 +163,12 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
*/
protected abstract void onBufferEnd();
- protected BroadcastReceiver notificationReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- int type = intent.getIntExtra(
- PlaybackService.EXTRA_NOTIFICATION_TYPE, -1);
- int code = intent.getIntExtra(
- PlaybackService.EXTRA_NOTIFICATION_CODE, -1);
- if (code != -1 && type != -1) {
- switch (type) {
- case PlaybackService.NOTIFICATION_TYPE_ERROR:
- handleError(code);
- break;
- case PlaybackService.NOTIFICATION_TYPE_BUFFER_UPDATE:
- if (sbPosition != null) {
- float progress = ((float) code) / 100;
- sbPosition.setSecondaryProgress((int) progress
- * sbPosition.getMax());
- }
- break;
- case PlaybackService.NOTIFICATION_TYPE_RELOAD:
- if (positionObserver != null) {
- positionObserver.cancel(true);
- positionObserver = null;
- }
- mediaInfoLoaded = false;
- onReloadNotification(intent.getIntExtra(
- PlaybackService.EXTRA_NOTIFICATION_CODE, -1));
- queryService();
-
- break;
- case PlaybackService.NOTIFICATION_TYPE_SLEEPTIMER_UPDATE:
- invalidateOptionsMenu();
- break;
- case PlaybackService.NOTIFICATION_TYPE_BUFFER_START:
- onBufferStart();
- break;
- case PlaybackService.NOTIFICATION_TYPE_BUFFER_END:
- onBufferEnd();
- break;
- }
-
- } else {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Bad arguments. Won't handle intent");
- }
-
+ protected void onBufferUpdate(float progress) {
+ if (sbPosition != null) {
+ sbPosition.setSecondaryProgress((int) progress
+ * sbPosition.getMax());
}
-
- };
+ }
/** Current screen orientation. */
protected int orientation;
@@ -225,26 +178,7 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
super.onStop();
if (AppConfig.DEBUG)
Log.d(TAG, "Activity stopped");
- try {
- unregisterReceiver(statusUpdate);
- } catch (IllegalArgumentException e) {
- // ignore
- }
-
- try {
- unregisterReceiver(notificationReceiver);
- } catch (IllegalArgumentException e) {
- // ignore
- }
-
- try {
- unbindService(mConnection);
- } catch (IllegalArgumentException e) {
- // ignore
- }
- if (positionObserver != null) {
- positionObserver.cancel(true);
- }
+ controller.release();
}
@Override
@@ -256,6 +190,7 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
+ FeedMedia media = controller.getMedia();
menu.findItem(R.id.support_item).setVisible(
media != null && media.getItem().getPaymentLink() != null);
@@ -264,10 +199,8 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
menu.findItem(R.id.visit_website_item).setVisible(
media != null && media.getItem().getLink() != null);
- boolean sleepTimerSet = playbackService != null
- && playbackService.sleepTimerActive();
- boolean sleepTimerNotSet = playbackService != null
- && !playbackService.sleepTimerActive();
+ boolean sleepTimerSet = controller.sleepTimerActive();
+ boolean sleepTimerNotSet = controller.sleepTimerNotActive();
menu.findItem(R.id.set_sleeptimer_item).setVisible(sleepTimerNotSet);
menu.findItem(R.id.disable_sleeptimer_item).setVisible(sleepTimerSet);
return true;
@@ -281,11 +214,11 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
MainActivity.class));
break;
case R.id.disable_sleeptimer_item:
- if (playbackService != null) {
+ if (controller.serviceAvailable()) {
AlertDialog.Builder stDialog = new AlertDialog.Builder(this);
stDialog.setTitle(R.string.sleep_timer_label);
stDialog.setMessage(getString(R.string.time_left_label)
- + Converter.getDurationStringLong((int) playbackService
+ + Converter.getDurationStringLong((int) controller
.getSleepTimerTimeLeft()));
stDialog.setPositiveButton(R.string.disable_sleeptimer_label,
new DialogInterface.OnClickListener() {
@@ -294,9 +227,7 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
public void onClick(DialogInterface dialog,
int which) {
dialog.dismiss();
- if (playbackService != null) {
- playbackService.disableSleepTimer();
- }
+ controller.disableSleepTimer();
}
});
stDialog.setNegativeButton(R.string.cancel_label,
@@ -312,16 +243,14 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
}
break;
case R.id.set_sleeptimer_item:
- if (playbackService != null) {
+ if (controller.serviceAvailable()) {
TimeDialog td = new TimeDialog(this,
R.string.set_sleeptimer_label,
R.string.set_sleeptimer_label) {
@Override
public void onTimeEntered(long millis) {
- if (playbackService != null) {
- playbackService.setSleepTimer(millis);
- }
+ controller.setSleepTimer(millis);
}
};
td.show();
@@ -329,8 +258,8 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
}
default:
- return FeedItemMenuHandler.onMenuItemClicked(this, item,
- media.getItem());
+ return FeedItemMenuHandler.onMenuItemClicked(this, item, controller
+ .getMedia().getItem());
}
return true;
}
@@ -341,8 +270,7 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
if (AppConfig.DEBUG)
Log.d(TAG, "Resuming Activity");
StorageUtils.checkStorageAvailability(this);
- bindToService();
-
+ controller.init();
}
@Override
@@ -353,101 +281,6 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
}
/**
- * Tries to establish a connection to the PlaybackService. If it isn't
- * running, the PlaybackService will be started with the last played media
- * as the arguments of the launch intent.
- */
- protected void bindToService() {
- Intent serviceIntent = new Intent(this, PlaybackService.class);
- boolean bound = false;
- if (!PlaybackService.isRunning) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Trying to restore last played media");
- SharedPreferences prefs = getApplicationContext()
- .getSharedPreferences(PodcastApp.PREF_NAME, 0);
- long mediaId = prefs.getLong(PlaybackService.PREF_LAST_PLAYED_ID,
- -1);
- long feedId = prefs.getLong(
- PlaybackService.PREF_LAST_PLAYED_FEED_ID, -1);
- if (mediaId != -1 && feedId != -1) {
- serviceIntent.putExtra(PlaybackService.EXTRA_FEED_ID, feedId);
- serviceIntent.putExtra(PlaybackService.EXTRA_MEDIA_ID, mediaId);
- serviceIntent.putExtra(
- PlaybackService.EXTRA_START_WHEN_PREPARED, false);
- serviceIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM,
- prefs.getBoolean(PlaybackService.PREF_LAST_IS_STREAM,
- true));
- startService(serviceIntent);
- bound = bindService(serviceIntent, mConnection,
- Context.BIND_AUTO_CREATE);
- } else {
- if (AppConfig.DEBUG)
- Log.d(TAG, "No last played media found");
- status = PlayerStatus.STOPPED;
- setupGUI();
- handleStatus();
- }
- } else {
- bound = bindService(serviceIntent, mConnection, 0);
- }
- if (AppConfig.DEBUG)
- Log.d(TAG, "Result for service binding: " + bound);
- }
-
- /**
- * Is called whenever the PlaybackService changes it's status. This method
- * should be used to update the GUI or start/cancel AsyncTasks.
- */
- private void handleStatus() {
- switch (status) {
-
- case ERROR:
- postStatusMsg(R.string.player_error_msg);
- break;
- case PAUSED:
- postStatusMsg(R.string.player_paused_msg);
- loadMediaInfo();
- if (positionObserver != null) {
- positionObserver.cancel(true);
- positionObserver = null;
- }
- butPlay.setImageResource(R.drawable.av_play);
- break;
- case PLAYING:
- clearStatusMsg();
- loadMediaInfo();
- setupPositionObserver();
- butPlay.setImageResource(R.drawable.av_pause);
- break;
- case PREPARING:
- postStatusMsg(R.string.player_preparing_msg);
- loadMediaInfo();
- if (playbackService != null) {
- if (playbackService.isStartWhenPrepared()) {
- butPlay.setImageResource(R.drawable.av_pause);
- } else {
- butPlay.setImageResource(R.drawable.av_play);
- }
- }
- break;
- case STOPPED:
- postStatusMsg(R.string.player_stopped_msg);
- break;
- case PREPARED:
- loadMediaInfo();
- postStatusMsg(R.string.player_ready_msg);
- butPlay.setImageResource(R.drawable.av_play);
- break;
- case SEEKING:
- postStatusMsg(R.string.player_seeking_msg);
- break;
- case AWAITING_VIDEO_SURFACE:
- onAwaitingVideoSurface();
- break;
- }
- }
-
- /**
* Called by 'handleStatus()' when the PlaybackService is in the
* AWAITING_VIDEO_SURFACE state.
*/
@@ -458,45 +291,25 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
protected abstract void clearStatusMsg();
protected void onPositionObserverUpdate() {
- int currentPosition = playbackService.getPlayer().getCurrentPosition();
- media.setPosition(currentPosition);
- txtvPosition.setText(Converter.getDurationStringLong(currentPosition));
- txtvLength.setText(Converter.getDurationStringLong(playbackService
- .getPlayer().getDuration()));
- updateProgressbarPosition();
- }
-
- @SuppressLint("NewApi")
- private void setupPositionObserver() {
- if (positionObserver == null || positionObserver.isCancelled()) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Setting up position observer");
- positionObserver = new MediaPositionObserver() {
-
- @Override
- protected void onProgressUpdate(Void... v) {
- super.onProgressUpdate();
- onPositionObserverUpdate();
- }
-
- };
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- positionObserver.executeOnExecutor(
- AsyncTask.THREAD_POOL_EXECUTOR,
- playbackService.getPlayer());
- } else {
- positionObserver.execute(playbackService.getPlayer());
- }
-
+ int currentPosition = controller.getPosition();
+ int duration = controller.getDuration();
+ if (currentPosition != PlaybackController.INVALID_TIME
+ && duration != PlaybackController.INVALID_TIME) {
+ controller.getMedia().setPosition(currentPosition);
+ txtvPosition.setText(Converter
+ .getDurationStringLong(currentPosition));
+ txtvLength.setText(Converter.getDurationStringLong(duration));
+ updateProgressbarPosition(currentPosition, duration);
+ } else {
+ Log.w(TAG,
+ "Could not react to position observer update because of invalid time");
}
}
- private void updateProgressbarPosition() {
+ private void updateProgressbarPosition(int position, int duration) {
if (AppConfig.DEBUG)
Log.d(TAG, "Updating progressbar info");
- MediaPlayer player = playbackService.getPlayer();
- float progress = ((float) player.getCurrentPosition())
- / player.getDuration();
+ float progress = ((float) position) / duration;
sbPosition.setProgress((int) (progress * sbPosition.getMax()));
}
@@ -507,26 +320,23 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
* FeedMedia object.
*/
protected void loadMediaInfo() {
- if (!mediaInfoLoaded) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Loading media info");
- if (media != null) {
- getSupportActionBar().setSubtitle(media.getItem().getTitle());
- getSupportActionBar().setTitle(
- media.getItem().getFeed().getTitle());
- txtvPosition.setText(Converter.getDurationStringLong((media
- .getPosition())));
-
- if (media.getDuration() != 0) {
- txtvLength.setText(Converter.getDurationStringLong(media
- .getDuration()));
- float progress = ((float) media.getPosition())
- / media.getDuration();
- sbPosition.setProgress((int) (progress * sbPosition
- .getMax()));
- }
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Loading media info");
+ FeedMedia media = controller.getMedia();
+ if (media != null) {
+ getSupportActionBar().setSubtitle(media.getItem().getTitle());
+ getSupportActionBar()
+ .setTitle(media.getItem().getFeed().getTitle());
+ txtvPosition.setText(Converter.getDurationStringLong((media
+ .getPosition())));
+
+ if (media.getDuration() != 0) {
+ txtvLength.setText(Converter.getDurationStringLong(media
+ .getDuration()));
+ float progress = ((float) media.getPosition())
+ / media.getDuration();
+ sbPosition.setProgress((int) (progress * sbPosition.getMax()));
}
- mediaInfoLoaded = true;
}
}
@@ -545,25 +355,12 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
// BUTTON SETUP
- butPlay.setOnClickListener(playbuttonListener);
+ butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
- butFF.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (status == PlayerStatus.PLAYING) {
- playbackService.seekDelta(DEFAULT_SEEK_DELTA);
- }
- }
- });
+ butFF.setOnClickListener(controller.newOnFFButtonClickListener());
+
+ butRev.setOnClickListener(controller.newOnRevButtonClickListener());
- butRev.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (status == PlayerStatus.PLAYING) {
- playbackService.seekDelta(-DEFAULT_SEEK_DELTA);
- }
- }
- });
}
void handleError(int errorCode) {
@@ -582,100 +379,24 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
errorDialog.create().show();
}
- /**
- * Called when connection to playback service has been established or
- * information has to be refreshed
- */
- void queryService() {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Querying service info");
- if (playbackService != null) {
- status = playbackService.getStatus();
- media = playbackService.getMedia();
- invalidateOptionsMenu();
-
- setupGUI();
- handleStatus();
-
- } else {
- Log.e(TAG,
- "queryService() was called without an existing connection to playbackservice");
- }
- }
-
- /** Refreshes the current position of the media file that is playing. */
- public class MediaPositionObserver extends
- AsyncTask<MediaPlayer, Void, Void> {
-
- private static final String TAG = "MediaPositionObserver";
- private static final int WAITING_INTERVALL = 1000;
- private MediaPlayer player;
-
- @Override
- protected void onCancelled() {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Task was cancelled");
- }
-
- @Override
- protected Void doInBackground(MediaPlayer... p) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Background Task started");
- player = p[0];
- try {
- while (player.isPlaying() && !isCancelled()) {
- try {
- Thread.sleep(WAITING_INTERVALL);
- } catch (InterruptedException e) {
- if (AppConfig.DEBUG)
- Log.d(TAG,
- "Thread was interrupted while waiting. Finishing now");
- return null;
- }
- publishProgress();
-
- }
- } catch (IllegalStateException e) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "player is in illegal state, exiting now");
- }
- if (AppConfig.DEBUG)
- Log.d(TAG, "Background Task finished");
- return null;
- }
- }
-
- // OnSeekbarChangeListener
- private int duration;
- private float prog;
+ float prog;
+ int duration;
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
- if (fromUser && PlaybackService.isRunning) {
- prog = progress / ((float) seekBar.getMax());
- duration = playbackService.getPlayer().getDuration();
- txtvPosition.setText(Converter
- .getDurationStringLong((int) (prog * duration)));
- }
-
+ controller.onSeekBarProgressChanged(seekBar, progress, fromUser, prog,
+ duration, txtvPosition);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
- // interrupt position Observer, restart later
- if (positionObserver != null) {
- positionObserver.cancel(true);
- positionObserver = null;
- }
+ controller.onSeekBarStartTrackingTouch(seekBar);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
- if (PlaybackService.isRunning) {
- playbackService.seek((int) (prog * duration));
- setupPositionObserver();
- }
+ controller.onSeekBarStopTrackingTouch(seekBar, prog, duration);
}
}
diff --git a/src/de/danoeh/antennapod/activity/VideoplayerActivity.java b/src/de/danoeh/antennapod/activity/VideoplayerActivity.java
index ddeef7ef0..d8a03b9d9 100644
--- a/src/de/danoeh/antennapod/activity/VideoplayerActivity.java
+++ b/src/de/danoeh/antennapod/activity/VideoplayerActivity.java
@@ -18,7 +18,6 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.service.PlaybackService;
import de.danoeh.antennapod.service.PlayerStatus;
-
/** Activity for playing audio files. */
public class VideoplayerActivity extends MediaplayerActivity implements
SurfaceHolder.Callback {
@@ -44,19 +43,6 @@ public class VideoplayerActivity extends MediaplayerActivity implements
if (videoControlsToggler != null) {
videoControlsToggler.cancel(true);
}
- if (PlaybackService.isRunning && playbackService != null
- && PlaybackService.isPlayingVideo()) {
- playbackService.pause(true);
- }
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- if (PlaybackService.isRunning && playbackService != null
- && PlaybackService.isPlayingVideo()) {
- playbackService.stop();
- }
}
@Override
@@ -66,7 +52,6 @@ public class VideoplayerActivity extends MediaplayerActivity implements
videoview = (VideoView) findViewById(R.id.videoview);
progressIndicator = (ProgressBar) findViewById(R.id.progressIndicator);
videoview.getHolder().addCallback(this);
- videoview.setOnClickListener(playbuttonListener);
videoview.setOnTouchListener(onVideoviewTouched);
setupVideoControlsToggler();
@@ -80,7 +65,7 @@ public class VideoplayerActivity extends MediaplayerActivity implements
if (AppConfig.DEBUG)
Log.d(TAG,
"Videosurface already created, setting videosurface now");
- playbackService.setVideoSurface(videoview.getHolder());
+ controller.setVideoSurface(videoview.getHolder());
}
}
@@ -194,9 +179,9 @@ public class VideoplayerActivity extends MediaplayerActivity implements
if (AppConfig.DEBUG)
Log.d(TAG, "Videoview holder created");
videoSurfaceCreated = true;
- if (status == PlayerStatus.AWAITING_VIDEO_SURFACE) {
- if (playbackService != null) {
- playbackService.setVideoSurface(holder);
+ if (controller.getStatus() == PlayerStatus.AWAITING_VIDEO_SURFACE) {
+ if (controller.serviceAvailable()) {
+ controller.setVideoSurface(holder);
} else {
Log.e(TAG,
"Could'nt attach surface to mediaplayer - reference to service was null");
diff --git a/src/de/danoeh/antennapod/util/PlaybackController.java b/src/de/danoeh/antennapod/util/PlaybackController.java
new file mode 100644
index 000000000..94deb0c77
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/PlaybackController.java
@@ -0,0 +1,565 @@
+package de.danoeh.antennapod.util;
+
+import de.danoeh.antennapod.AppConfig;
+import de.danoeh.antennapod.PodcastApp;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.feed.SimpleChapter;
+import de.danoeh.antennapod.service.PlaybackService;
+import de.danoeh.antennapod.service.PlayerStatus;
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.media.MediaPlayer;
+import android.os.AsyncTask;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.SurfaceHolder;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ImageButton;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.widget.TextView;
+
+/** Communicates with the playback service. */
+public abstract class PlaybackController {
+ private static final String TAG = "PlaybackController";
+
+ /**
+ * Returned by getPosition() or getDuration() if the playbackService is in
+ * an invalid state.
+ */
+ public static final int INVALID_TIME = -1;
+
+ static final int DEFAULT_SEEK_DELTA = 30000;
+
+ private Activity activity;
+
+ private PlaybackService playbackService;
+ private FeedMedia media;
+ private PlayerStatus status;
+
+ protected MediaPositionObserver positionObserver;
+
+ private boolean mediaInfoLoaded = false;
+
+ public PlaybackController(Activity activity) {
+ this.activity = activity;
+ }
+
+ /**
+ * Creates a new connection to the playbackService. Should be called in the
+ * activity's onResume() method.
+ */
+ public void init() {
+ bindToService();
+ }
+
+ /**
+ * Should be called if the PlaybackController is no longer needed, for
+ * example in the activity's onStop() method.
+ */
+ public void release() {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Releasing PlaybackController");
+
+ try {
+ activity.unregisterReceiver(statusUpdate);
+ } catch (IllegalArgumentException e) {
+ // ignore
+ }
+
+ try {
+ activity.unregisterReceiver(notificationReceiver);
+ } catch (IllegalArgumentException e) {
+ // ignore
+ }
+
+ try {
+ activity.unbindService(mConnection);
+ } catch (IllegalArgumentException e) {
+ // ignore
+ }
+ if (positionObserver != null) {
+ positionObserver.cancel(true);
+ }
+ }
+
+ /** Should be called in the activity's onPause() method. */
+ public void pause() {
+ mediaInfoLoaded = false;
+ if (playbackService != null && playbackService.isPlayingVideo()) {
+ playbackService.pause(true);
+ }
+ }
+
+ /**
+ * Tries to establish a connection to the PlaybackService. If it isn't
+ * running, the PlaybackService will be started with the last played media
+ * as the arguments of the launch intent.
+ */
+ private void bindToService() {
+ Intent serviceIntent = new Intent(activity, PlaybackService.class);
+ boolean bound = false;
+ if (!PlaybackService.isRunning) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Trying to restore last played media");
+ SharedPreferences prefs = activity.getApplicationContext()
+ .getSharedPreferences(PodcastApp.PREF_NAME, 0);
+ long mediaId = prefs.getLong(PlaybackService.PREF_LAST_PLAYED_ID,
+ -1);
+ long feedId = prefs.getLong(
+ PlaybackService.PREF_LAST_PLAYED_FEED_ID, -1);
+ if (mediaId != -1 && feedId != -1) {
+ serviceIntent.putExtra(PlaybackService.EXTRA_FEED_ID, feedId);
+ serviceIntent.putExtra(PlaybackService.EXTRA_MEDIA_ID, mediaId);
+ serviceIntent.putExtra(
+ PlaybackService.EXTRA_START_WHEN_PREPARED, false);
+ serviceIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM,
+ prefs.getBoolean(PlaybackService.PREF_LAST_IS_STREAM,
+ true));
+ activity.startService(serviceIntent);
+ bound = activity.bindService(serviceIntent, mConnection,
+ Context.BIND_AUTO_CREATE);
+ } else {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "No last played media found");
+ status = PlayerStatus.STOPPED;
+ setupGUI();
+ handleStatus();
+ }
+ } else {
+ bound = activity.bindService(serviceIntent, mConnection, 0);
+ }
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Result for service binding: " + bound);
+ }
+
+ public abstract void setupGUI();
+
+ @SuppressLint("NewApi")
+ private void setupPositionObserver() {
+ if (positionObserver == null || positionObserver.isCancelled()) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Setting up position observer");
+ positionObserver = new MediaPositionObserver() {
+
+ @Override
+ protected void onProgressUpdate(Void... v) {
+ super.onProgressUpdate();
+ onPositionObserverUpdate();
+ }
+
+ };
+ if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
+ positionObserver.executeOnExecutor(
+ AsyncTask.THREAD_POOL_EXECUTOR,
+ playbackService.getPlayer());
+ } else {
+ positionObserver.execute(playbackService.getPlayer());
+ }
+
+ }
+ }
+
+ public abstract void onPositionObserverUpdate();
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ playbackService = ((PlaybackService.LocalBinder) service)
+ .getService();
+
+ activity.registerReceiver(statusUpdate, new IntentFilter(
+ PlaybackService.ACTION_PLAYER_STATUS_CHANGED));
+
+ activity.registerReceiver(notificationReceiver, new IntentFilter(
+ PlaybackService.ACTION_PLAYER_NOTIFICATION));
+
+ queryService();
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Connection to Service established");
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ playbackService = null;
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Disconnected from Service");
+
+ }
+ };
+
+ protected BroadcastReceiver statusUpdate = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Received statusUpdate Intent.");
+ if (playbackService != null) {
+ status = playbackService.getStatus();
+ handleStatus();
+ } else {
+ Log.w(TAG,
+ "Couldn't receive status update: playbackService was null");
+ }
+ }
+ };
+
+ protected BroadcastReceiver notificationReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int type = intent.getIntExtra(
+ PlaybackService.EXTRA_NOTIFICATION_TYPE, -1);
+ int code = intent.getIntExtra(
+ PlaybackService.EXTRA_NOTIFICATION_CODE, -1);
+ if (code != -1 && type != -1) {
+ switch (type) {
+ case PlaybackService.NOTIFICATION_TYPE_ERROR:
+ handleError(code);
+ break;
+ case PlaybackService.NOTIFICATION_TYPE_BUFFER_UPDATE:
+ float progress = ((float) code) / 100;
+ onBufferUpdate(progress);
+ break;
+ case PlaybackService.NOTIFICATION_TYPE_RELOAD:
+ if (positionObserver != null) {
+ positionObserver.cancel(true);
+ positionObserver = null;
+ }
+ mediaInfoLoaded = false;
+ onReloadNotification(intent.getIntExtra(
+ PlaybackService.EXTRA_NOTIFICATION_CODE, -1));
+ queryService();
+
+ break;
+ case PlaybackService.NOTIFICATION_TYPE_SLEEPTIMER_UPDATE:
+ onSleepTimerUpdate();
+ break;
+ case PlaybackService.NOTIFICATION_TYPE_BUFFER_START:
+ onBufferStart();
+ break;
+ case PlaybackService.NOTIFICATION_TYPE_BUFFER_END:
+ onBufferEnd();
+ break;
+ }
+
+ } else {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Bad arguments. Won't handle intent");
+ }
+
+ }
+
+ };
+
+ /** Called when the currently displayed information should be refreshed. */
+ public abstract void onReloadNotification(int code);
+
+ public abstract void onBufferStart();
+
+ public abstract void onBufferEnd();
+
+ public abstract void onBufferUpdate(float progress);
+
+ public abstract void onSleepTimerUpdate();
+
+ public abstract void handleError(int code);
+
+ /**
+ * Is called whenever the PlaybackService changes it's status. This method
+ * should be used to update the GUI or start/cancel AsyncTasks.
+ */
+ private void handleStatus() {
+ switch (status) {
+
+ case ERROR:
+ postStatusMsg(R.string.player_error_msg);
+ break;
+ case PAUSED:
+ postStatusMsg(R.string.player_paused_msg);
+ checkMediaInfoLoaded();
+ if (positionObserver != null) {
+ positionObserver.cancel(true);
+ positionObserver = null;
+ }
+ updatePlayButtonAppearance(R.drawable.av_play);
+ break;
+ case PLAYING:
+ clearStatusMsg();
+ checkMediaInfoLoaded();
+ setupPositionObserver();
+ updatePlayButtonAppearance(R.drawable.av_pause);
+ break;
+ case PREPARING:
+ postStatusMsg(R.string.player_preparing_msg);
+ checkMediaInfoLoaded();
+ if (playbackService != null) {
+ if (playbackService.isStartWhenPrepared()) {
+ updatePlayButtonAppearance(R.drawable.av_pause);
+ } else {
+ updatePlayButtonAppearance(R.drawable.av_play);
+ }
+ }
+ break;
+ case STOPPED:
+ postStatusMsg(R.string.player_stopped_msg);
+ break;
+ case PREPARED:
+ checkMediaInfoLoaded();
+ postStatusMsg(R.string.player_ready_msg);
+ updatePlayButtonAppearance(R.drawable.av_play);
+ break;
+ case SEEKING:
+ postStatusMsg(R.string.player_seeking_msg);
+ break;
+ case AWAITING_VIDEO_SURFACE:
+ onAwaitingVideoSurface();
+ break;
+ }
+ }
+
+ private void checkMediaInfoLoaded() {
+ if (!mediaInfoLoaded) {
+ loadMediaInfo();
+ }
+ mediaInfoLoaded = true;
+ }
+
+ private void updatePlayButtonAppearance(int resource) {
+ ImageButton butPlay = getPlayButton();
+ butPlay.setImageResource(resource);
+ }
+
+ public abstract ImageButton getPlayButton();
+
+ public abstract void postStatusMsg(int msg);
+
+ public abstract void clearStatusMsg();
+
+ public abstract void loadMediaInfo();
+
+ public abstract void onAwaitingVideoSurface();
+
+ /**
+ * Called when connection to playback service has been established or
+ * information has to be refreshed
+ */
+ void queryService() {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Querying service info");
+ if (playbackService != null) {
+ status = playbackService.getStatus();
+ media = playbackService.getMedia();
+ onServiceQueried();
+
+ setupGUI();
+ handleStatus();
+
+ } else {
+ Log.e(TAG,
+ "queryService() was called without an existing connection to playbackservice");
+ }
+ }
+
+ public abstract void onServiceQueried();
+
+ /** Refreshes the current position of the media file that is playing. */
+ public class MediaPositionObserver extends
+ AsyncTask<MediaPlayer, Void, Void> {
+
+ private static final String TAG = "MediaPositionObserver";
+ private static final int WAITING_INTERVALL = 1000;
+ private MediaPlayer player;
+
+ @Override
+ protected void onCancelled() {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Task was cancelled");
+ }
+
+ @Override
+ protected Void doInBackground(MediaPlayer... p) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Background Task started");
+ player = p[0];
+ try {
+ while (player.isPlaying() && !isCancelled()) {
+ try {
+ Thread.sleep(WAITING_INTERVALL);
+ } catch (InterruptedException e) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG,
+ "Thread was interrupted while waiting. Finishing now");
+ return null;
+ }
+ publishProgress();
+
+ }
+ } catch (IllegalStateException e) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "player is in illegal state, exiting now");
+ }
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Background Task finished");
+ return null;
+ }
+ }
+
+ /**
+ * Should be used by classes which implement the OnSeekBarChanged interface.
+ */
+ public void onSeekBarProgressChanged(SeekBar seekBar, int progress,
+ boolean fromUser, float prog, int duration, TextView txtvPosition) {
+ if (fromUser && PlaybackService.isRunning) {
+ prog = progress / ((float) seekBar.getMax());
+ duration = playbackService.getPlayer().getDuration();
+ txtvPosition.setText(Converter
+ .getDurationStringLong((int) (prog * duration)));
+ }
+
+ }
+
+ /**
+ * Should be used by classes which implement the OnSeekBarChanged interface.
+ */
+ public void onSeekBarStartTrackingTouch(SeekBar seekBar) {
+ // interrupt position Observer, restart later
+ if (positionObserver != null) {
+ positionObserver.cancel(true);
+ positionObserver = null;
+ }
+ }
+
+ /**
+ * Should be used by classes which implement the OnSeekBarChanged interface.
+ */
+ public void onSeekBarStopTrackingTouch(SeekBar seekBar, float prog, int duration) {
+ if (PlaybackService.isRunning) {
+ playbackService.seek((int) (prog * duration));
+ setupPositionObserver();
+ }
+ }
+
+ public OnClickListener newOnPlayButtonClickListener() {
+ return new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (playbackService != null) {
+ switch (status) {
+ case PLAYING:
+ playbackService.pause(true);
+ break;
+ case PAUSED:
+ case PREPARED:
+ playbackService.play();
+ break;
+ case PREPARING:
+ playbackService.setStartWhenPrepared(!playbackService
+ .isStartWhenPrepared());
+ }
+ } else {
+ Log.w(TAG,
+ "Play/Pause button was pressed, but playbackservice was null!");
+ }
+ }
+
+ };
+ }
+
+ public OnClickListener newOnRevButtonClickListener() {
+ return new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (status == PlayerStatus.PLAYING) {
+ playbackService.seekDelta(-DEFAULT_SEEK_DELTA);
+ }
+ }
+ };
+ }
+
+ public OnClickListener newOnFFButtonClickListener() {
+ return new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (status == PlayerStatus.PLAYING) {
+ playbackService.seekDelta(DEFAULT_SEEK_DELTA);
+ }
+ }
+ };
+ }
+
+ public boolean serviceAvailable() {
+ return playbackService != null;
+ }
+
+ public int getPosition() {
+ if (playbackService != null) {
+ return playbackService.getPlayer().getCurrentPosition();
+ } else {
+ return INVALID_TIME;
+ }
+ }
+
+ public int getDuration() {
+ if (playbackService != null) {
+ return playbackService.getPlayer().getDuration();
+ } else {
+ return INVALID_TIME;
+ }
+ }
+
+ public FeedMedia getMedia() {
+ return media;
+ }
+
+ public boolean sleepTimerActive() {
+ return playbackService != null && playbackService.sleepTimerActive();
+ }
+
+ public boolean sleepTimerNotActive() {
+ return playbackService != null && !playbackService.sleepTimerActive();
+ }
+
+ public void disableSleepTimer() {
+ if (playbackService != null) {
+ playbackService.disableSleepTimer();
+ }
+ }
+
+ public long getSleepTimerTimeLeft() {
+ if (playbackService != null) {
+ return playbackService.getSleepTimerTimeLeft();
+ } else {
+ return INVALID_TIME;
+ }
+ }
+
+ public void setSleepTimer(long time) {
+ if (playbackService != null) {
+ playbackService.setSleepTimer(time);
+ }
+ }
+
+ public void seekToChapter(SimpleChapter chapter) {
+ if (playbackService != null) {
+ playbackService.seekToChapter(chapter);
+ }
+ }
+
+ public void setVideoSurface(SurfaceHolder holder) {
+ if (playbackService != null) {
+ playbackService.setVideoSurface(holder);
+ }
+ }
+
+ public PlayerStatus getStatus() {
+ return status;
+ }
+}