Rewrote most parts of PlaybackService and Mediaplayer Activity
This commit is contained in:
parent
940f133e4c
commit
524161783a
|
@ -8,6 +8,7 @@
|
|||
<item android:id="@+id/mark_unread_item" android:title="@string/mark_unread_label" android:visible="false" android:showAsAction="collapseActionView"></item>
|
||||
<item android:id="@+id/add_to_queue_item" android:title="@string/add_to_queue_label" android:visible="false" android:showAsAction="collapseActionView"></item>
|
||||
<item android:id="@+id/remove_from_queue_item" android:title="@string/remove_from_queue_label" android:visible="false" android:showAsAction="collapseActionView"></item>
|
||||
<item android:id="@+id/stream_item" android:title="@string/stream_label" android:visible="false" android:showAsAction="collapseActionView"></item>
|
||||
|
||||
|
||||
</menu>
|
|
@ -35,7 +35,7 @@
|
|||
<!-- Mediaplayer status Messages -->
|
||||
<string name="player_paused_msg">Paused</string>
|
||||
<string name="player_error_msg">Error!</string>
|
||||
<string name="player_stopped_msg">Stopped</string>
|
||||
<string name="player_stopped_msg">No media playing</string>
|
||||
<string name="player_preparing_msg">Preparing...</string>
|
||||
<string name="mark_read_label">Mark read</string>
|
||||
<string name="mark_unread_label">Mark unread</string>
|
||||
|
@ -51,4 +51,6 @@
|
|||
<string name="show_player_label">Show player</string>
|
||||
<string name="add_to_queue_label">Add to Queue</string>
|
||||
<string name="remove_from_queue_label">Remove from Queue</string>
|
||||
<string name="player_ready_msg">Ready</string>
|
||||
<string name="stream_label">Stream</string>
|
||||
</resources>
|
||||
|
|
|
@ -6,6 +6,8 @@ import android.app.Application;
|
|||
|
||||
public class PodcastApp extends Application {
|
||||
private static final String TAG = "PodcastApp";
|
||||
public static final String PREF_NAME = "PodfetcherPrefs";
|
||||
|
||||
|
||||
private static PodcastApp singleton;
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ public class ItemviewActivity extends SherlockActivity {
|
|||
butPlay.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
manager.playMedia(v.getContext(), item.getMedia());
|
||||
//manager.playMedia(v.getContext(), item.getMedia());
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ 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.Bundle;
|
||||
|
@ -22,7 +23,9 @@ import android.widget.TextView;
|
|||
import com.actionbarsherlock.app.SherlockActivity;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
|
||||
import de.podfetcher.PodcastApp;
|
||||
import de.podfetcher.R;
|
||||
import de.podfetcher.feed.FeedManager;
|
||||
import de.podfetcher.feed.FeedMedia;
|
||||
import de.podfetcher.service.PlaybackService;
|
||||
import de.podfetcher.service.PlayerStatus;
|
||||
|
@ -30,16 +33,18 @@ import de.podfetcher.util.Converter;
|
|||
|
||||
public class MediaplayerActivity extends SherlockActivity {
|
||||
private final String TAG = "MediaplayerActivity";
|
||||
|
||||
private static final int DEFAULT_SEEK_DELTA = 30000; // Seek-Delta to use when using FF or Rev Buttons
|
||||
|
||||
|
||||
private static final int DEFAULT_SEEK_DELTA = 30000; // Seek-Delta to use
|
||||
// when using FF or
|
||||
// Rev Buttons
|
||||
|
||||
private PlaybackService playbackService;
|
||||
private MediaPositionObserver positionObserver;
|
||||
|
||||
|
||||
private FeedMedia media;
|
||||
private PlayerStatus status;
|
||||
|
||||
|
||||
private FeedManager manager;
|
||||
|
||||
// Widgets
|
||||
private ImageView imgvCover;
|
||||
private TextView txtvStatus;
|
||||
|
@ -49,7 +54,7 @@ public class MediaplayerActivity extends SherlockActivity {
|
|||
private ImageButton butPlay;
|
||||
private ImageButton butRev;
|
||||
private ImageButton butFF;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
|
@ -66,15 +71,13 @@ public class MediaplayerActivity extends SherlockActivity {
|
|||
// TODO Auto-generated method stub
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
Log.d(TAG, "Resuming Activity");
|
||||
bindToService();
|
||||
registerReceiver(statusUpdate, new IntentFilter(PlaybackService.ACTION_PLAYER_STATUS_CHANGED));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,22 +85,47 @@ public class MediaplayerActivity extends SherlockActivity {
|
|||
super.onCreate(savedInstanceState);
|
||||
Log.d(TAG, "Creating Activity");
|
||||
this.setContentView(R.layout.mediaplayer_activity);
|
||||
|
||||
manager = FeedManager.getInstance();
|
||||
setupGUI();
|
||||
bindToService();
|
||||
registerReceiver(statusUpdate, new IntentFilter(PlaybackService.ACTION_PLAYER_STATUS_CHANGED));
|
||||
}
|
||||
|
||||
|
||||
private void bindToService() {
|
||||
if(!bindService(new Intent(this, PlaybackService.class), mConnection, 0)) {
|
||||
status = PlayerStatus.STOPPED;
|
||||
handleStatus();
|
||||
Intent serviceIntent = new Intent(this, PlaybackService.class);
|
||||
boolean bound = false;
|
||||
if (!PlaybackService.isRunning) {
|
||||
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 {
|
||||
Log.d(TAG, "No last played media found");
|
||||
status = PlayerStatus.STOPPED;
|
||||
handleStatus();
|
||||
}
|
||||
} else {
|
||||
bound = bindService(serviceIntent, mConnection, 0);
|
||||
}
|
||||
Log.d(TAG, "Result for service binding: " + bound);
|
||||
}
|
||||
|
||||
|
||||
private void handleStatus() {
|
||||
switch (status) {
|
||||
|
||||
|
||||
case ERROR:
|
||||
setStatusMsg(R.string.player_error_msg, View.VISIBLE);
|
||||
handleError();
|
||||
|
@ -120,51 +148,73 @@ public class MediaplayerActivity extends SherlockActivity {
|
|||
case PREPARING:
|
||||
setStatusMsg(R.string.player_preparing_msg, View.VISIBLE);
|
||||
break;
|
||||
case STOPPED:
|
||||
setStatusMsg(R.string.player_stopped_msg, View.VISIBLE);
|
||||
imgvCover.setImageBitmap(null);
|
||||
break;
|
||||
case PREPARED:
|
||||
loadMediaInfo();
|
||||
setStatusMsg(R.string.player_ready_msg, View.VISIBLE);
|
||||
butPlay.setImageResource(android.R.drawable.ic_media_play);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void setStatusMsg(int resId, int visibility) {
|
||||
if(visibility == View.VISIBLE) {
|
||||
if (visibility == View.VISIBLE) {
|
||||
txtvStatus.setText(resId);
|
||||
}
|
||||
txtvStatus.setVisibility(visibility);
|
||||
}
|
||||
|
||||
|
||||
private void setupPositionObserver() {
|
||||
if (positionObserver == null) {
|
||||
if (positionObserver == null || positionObserver.isCancelled()) {
|
||||
positionObserver = new MediaPositionObserver() {
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... values) {
|
||||
super.onProgressUpdate(values);
|
||||
txtvPosition.setText(
|
||||
Converter.getDurationStringLong(values[0]));
|
||||
|
||||
float progress = ((float) values[0]) / getDuration();
|
||||
sbPosition.setProgress((int) (progress * 100));
|
||||
protected void onProgressUpdate(Void... v) {
|
||||
super.onProgressUpdate();
|
||||
txtvPosition.setText(Converter
|
||||
.getDurationStringLong(playbackService.getPlayer()
|
||||
.getCurrentPosition()));
|
||||
|
||||
updateProgressbarPosition();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
positionObserver.execute(playbackService.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void updateProgressbarPosition() {
|
||||
MediaPlayer player = playbackService.getPlayer();
|
||||
float progress = ((float) player.getCurrentPosition())
|
||||
/ player.getDuration();
|
||||
sbPosition.setProgress((int) (progress * sbPosition.getMax()));
|
||||
}
|
||||
|
||||
private void loadMediaInfo() {
|
||||
if (media != null) {
|
||||
MediaPlayer player = playbackService.getPlayer();
|
||||
|
||||
|
||||
getSupportActionBar().setSubtitle(media.getItem().getTitle());
|
||||
getSupportActionBar().setTitle(
|
||||
media.getItem().getFeed().getTitle());
|
||||
|
||||
imgvCover.setImageBitmap(
|
||||
media.getItem().getFeed().getImage().getImageBitmap());
|
||||
|
||||
txtvPosition.setText(Converter.getDurationStringLong((player.getCurrentPosition())));
|
||||
txtvLength.setText(Converter.getDurationStringLong(player.getDuration()));
|
||||
getSupportActionBar()
|
||||
.setTitle(media.getItem().getFeed().getTitle());
|
||||
|
||||
imgvCover.setImageBitmap(media.getItem().getFeed().getImage()
|
||||
.getImageBitmap());
|
||||
|
||||
txtvPosition.setText(Converter.getDurationStringLong((player
|
||||
.getCurrentPosition())));
|
||||
txtvLength.setText(Converter.getDurationStringLong(player
|
||||
.getDuration()));
|
||||
if (playbackService != null) {
|
||||
updateProgressbarPosition();
|
||||
} else {
|
||||
sbPosition.setProgress(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void setupGUI() {
|
||||
imgvCover = (ImageView) findViewById(R.id.imgvCover);
|
||||
txtvPosition = (TextView) findViewById(R.id.txtvPosition);
|
||||
|
@ -174,22 +224,23 @@ public class MediaplayerActivity extends SherlockActivity {
|
|||
butPlay = (ImageButton) findViewById(R.id.butPlay);
|
||||
butRev = (ImageButton) findViewById(R.id.butRev);
|
||||
butFF = (ImageButton) findViewById(R.id.butFF);
|
||||
|
||||
|
||||
sbPosition.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
|
||||
int duration;
|
||||
float prog;
|
||||
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress,
|
||||
boolean fromUser) {
|
||||
if (fromUser) {
|
||||
prog = progress / 100.0f;
|
||||
duration = playbackService.getPlayer().getDuration();
|
||||
txtvPosition.setText(Converter.getDurationStringLong((int) (prog * duration)));
|
||||
txtvPosition.setText(Converter
|
||||
.getDurationStringLong((int) (prog * duration)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
// interrupt position Observer, restart later
|
||||
|
@ -198,25 +249,26 @@ public class MediaplayerActivity extends SherlockActivity {
|
|||
positionObserver = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
playbackService.seek((int) (prog * duration));
|
||||
setupPositionObserver();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
butPlay.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (status == PlayerStatus.PLAYING) {
|
||||
playbackService.pause();
|
||||
} else if (status == PlayerStatus.PAUSED) {
|
||||
} else if (status == PlayerStatus.PAUSED
|
||||
|| status == PlayerStatus.PREPARED) {
|
||||
playbackService.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
butFF.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -225,7 +277,7 @@ public class MediaplayerActivity extends SherlockActivity {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
butRev.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -235,17 +287,19 @@ public class MediaplayerActivity extends SherlockActivity {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void handleError() {
|
||||
// TODO implement
|
||||
}
|
||||
|
||||
|
||||
private ServiceConnection mConnection = new ServiceConnection() {
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
playbackService = ((PlaybackService.LocalBinder)service).getService();
|
||||
playbackService = ((PlaybackService.LocalBinder) service)
|
||||
.getService();
|
||||
status = playbackService.getStatus();
|
||||
media = playbackService.getMedia();
|
||||
registerReceiver(statusUpdate, new IntentFilter(
|
||||
PlaybackService.ACTION_PLAYER_STATUS_CHANGED));
|
||||
handleStatus();
|
||||
Log.d(TAG, "Connection to Service established");
|
||||
}
|
||||
|
@ -254,55 +308,48 @@ public class MediaplayerActivity extends SherlockActivity {
|
|||
public void onServiceDisconnected(ComponentName name) {
|
||||
playbackService = null;
|
||||
Log.d(TAG, "Disconnected from Service");
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private BroadcastReceiver statusUpdate = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.d(TAG, "Received statusUpdate Intent.");
|
||||
Log.d(TAG, "Received statusUpdate Intent.");
|
||||
status = playbackService.getStatus();
|
||||
handleStatus();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Refreshes the current position of the media file that is playing. */
|
||||
public class MediaPositionObserver extends AsyncTask<MediaPlayer, Integer, Boolean> {
|
||||
|
||||
public class MediaPositionObserver extends
|
||||
AsyncTask<MediaPlayer, Void, Void> {
|
||||
|
||||
private static final int WAITING_INTERVALL = 1000;
|
||||
private MediaPlayer player;
|
||||
private int duration;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCancelled(Boolean result) {
|
||||
protected void onCancelled() {
|
||||
Log.d(TAG, "Task was cancelled");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(MediaPlayer... p) {
|
||||
protected Void doInBackground(MediaPlayer... p) {
|
||||
Log.d(TAG, "Background Task started");
|
||||
player = p[0];
|
||||
duration = player.getDuration();
|
||||
|
||||
while(player.isPlaying() && !isCancelled()) {
|
||||
|
||||
while (player.isPlaying() && !isCancelled()) {
|
||||
try {
|
||||
Thread.sleep(WAITING_INTERVALL);
|
||||
} catch(InterruptedException e) {
|
||||
Log.d(TAG, "Thread was interrupted while waiting. Finishing now");
|
||||
return false;
|
||||
} catch (InterruptedException e) {
|
||||
Log.d(TAG,
|
||||
"Thread was interrupted while waiting. Finishing now");
|
||||
}
|
||||
publishProgress(player.getCurrentPosition());
|
||||
publishProgress();
|
||||
}
|
||||
Log.d(TAG, "Background Task finished");
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getDuration() {
|
||||
return duration;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public class FeedManager {
|
|||
|
||||
/** Contains completed Download status entries */
|
||||
private ArrayList<DownloadStatus> downloadLog;
|
||||
|
||||
|
||||
/** Contains the queue of items to be played. */
|
||||
private ArrayList<FeedItem> queue;
|
||||
|
||||
|
@ -59,18 +59,31 @@ public class FeedManager {
|
|||
/**
|
||||
* Play FeedMedia and start the playback service + launch Mediaplayer
|
||||
* Activity.
|
||||
*
|
||||
* @param context
|
||||
* for starting the playbackservice
|
||||
* @param media
|
||||
* that shall be played
|
||||
* @param showPlayer
|
||||
* if Mediaplayer activity shall be started
|
||||
* @param startWhenPrepared
|
||||
* if Mediaplayer shall be started after it has been prepared
|
||||
*/
|
||||
public void playMedia(Context context, FeedMedia media) {
|
||||
public void playMedia(Context context, FeedMedia media, boolean showPlayer,
|
||||
boolean startWhenPrepared, boolean shouldStream) {
|
||||
// Start playback Service
|
||||
Intent launchIntent = new Intent(context, PlaybackService.class);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_MEDIA_ID, media.getId());
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_FEED_ID, media.getItem()
|
||||
.getFeed().getId());
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED, startWhenPrepared);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, shouldStream);
|
||||
context.startService(launchIntent);
|
||||
|
||||
// Launch Mediaplayer
|
||||
Intent playerIntent = new Intent(context, MediaplayerActivity.class);
|
||||
context.startActivity(playerIntent);
|
||||
if (showPlayer) {
|
||||
// Launch Mediaplayer
|
||||
Intent playerIntent = new Intent(context, MediaplayerActivity.class);
|
||||
context.startActivity(playerIntent);
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove media item that has been downloaded. */
|
||||
|
@ -88,14 +101,15 @@ public class FeedManager {
|
|||
Log.d(TAG, "Deleting File. Result: " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/** Remove a feed with all its items and media files and its image. */
|
||||
public boolean deleteFeed(Context context, Feed feed) {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
|
||||
|
||||
// delete image file
|
||||
if (feed.getImage() != null) {
|
||||
if (feed.getImage().isDownloaded() && feed.getImage().getFile_url() == null) {
|
||||
if (feed.getImage().isDownloaded()
|
||||
&& feed.getImage().getFile_url() == null) {
|
||||
File imageFile = new File(feed.getImage().getFile_url());
|
||||
imageFile.delete();
|
||||
}
|
||||
|
@ -112,7 +126,7 @@ public class FeedManager {
|
|||
}
|
||||
adapter.removeFeed(feed);
|
||||
return feeds.remove(feed);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -145,13 +159,13 @@ public class FeedManager {
|
|||
}
|
||||
return adapter.setDownloadStatus(status);
|
||||
}
|
||||
|
||||
|
||||
public void addQueueItem(Context context, FeedItem item) {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
queue.add(item);
|
||||
adapter.setQueue(queue);
|
||||
}
|
||||
|
||||
|
||||
public void removeQueueItem(Context context, FeedItem item) {
|
||||
boolean removed = queue.remove(item);
|
||||
if (removed) {
|
||||
|
@ -159,11 +173,15 @@ public class FeedManager {
|
|||
adapter.setQueue(queue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isInQueue(FeedItem item) {
|
||||
return queue.contains(item);
|
||||
}
|
||||
|
||||
public FeedItem getFirstQueueItem() {
|
||||
return queue.get(0);
|
||||
}
|
||||
|
||||
private void addNewFeed(Context context, Feed feed) {
|
||||
feeds.add(feed);
|
||||
feed.setId(setFeed(context, feed));
|
||||
|
@ -447,16 +465,19 @@ public class FeedManager {
|
|||
}
|
||||
adapter.close();
|
||||
}
|
||||
|
||||
|
||||
private void extractQueueFromCursor(Context context) {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
Cursor cursor = adapter.getQueueCursor();
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
int index = cursor.getInt(cursor.getColumnIndex(PodDBAdapter.KEY_ID));
|
||||
Feed feed = getFeed(cursor.getLong(cursor.getColumnIndex(PodDBAdapter.KEY_FEED)));
|
||||
FeedItem item = getFeedItem(cursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM), feed);
|
||||
int index = cursor.getInt(cursor
|
||||
.getColumnIndex(PodDBAdapter.KEY_ID));
|
||||
Feed feed = getFeed(cursor.getLong(cursor
|
||||
.getColumnIndex(PodDBAdapter.KEY_FEED)));
|
||||
FeedItem item = getFeedItem(
|
||||
cursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM), feed);
|
||||
queue.add(index, item);
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import android.app.PendingIntent;
|
|||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.media.AudioManager;
|
||||
|
@ -21,6 +22,7 @@ import android.os.AsyncTask;
|
|||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
|
||||
import de.podfetcher.PodcastApp;
|
||||
import de.podfetcher.activity.MediaplayerActivity;
|
||||
import de.podfetcher.feed.FeedMedia;
|
||||
import de.podfetcher.feed.Feed;
|
||||
|
@ -28,22 +30,46 @@ import de.podfetcher.feed.FeedManager;
|
|||
|
||||
/** Controls the MediaPlayer that plays a FeedMedia-file */
|
||||
public class PlaybackService extends Service {
|
||||
|
||||
/** Logging tag */
|
||||
private static final String TAG = "PlaybackService";
|
||||
|
||||
/** Contains the id of the media that was played last. */
|
||||
public static final String PREF_LAST_PLAYED_ID = "de.podfetcher.preferences.lastPlayedId";
|
||||
/** Contains the feed id of the last played item. */
|
||||
public static final String PREF_LAST_PLAYED_FEED_ID = "de.podfetcher.preferences.lastPlayedFeedId";
|
||||
/** True if last played media was streamed. */
|
||||
public static final String PREF_LAST_IS_STREAM = "de.podfetcher.preferences.lastIsStream";
|
||||
|
||||
|
||||
/** Contains the id of the FeedMedia object. */
|
||||
public static final String EXTRA_MEDIA_ID = "extra.de.podfetcher.service.mediaId";
|
||||
/** Contains the id of the Feed object of the FeedMedia. */
|
||||
public static final String EXTRA_FEED_ID = "extra.de.podfetcher.service.feedId";
|
||||
/** True if media should be streamed. */
|
||||
public static final String EXTRA_SHOULD_STREAM = "extra.de.podfetcher.service.shouldStream";
|
||||
/**
|
||||
* True if playback should be started immediately after media has been
|
||||
* prepared.
|
||||
*/
|
||||
public static final String EXTRA_START_WHEN_PREPARED = "extra.de.podfetcher.service.startWhenPrepared";
|
||||
|
||||
public static final String ACTION_PLAYER_STATUS_CHANGED = "action.de.podfetcher.service.playerStatusChanged";
|
||||
|
||||
/** Is true if service is running. */
|
||||
public static boolean isRunning = false;
|
||||
|
||||
private static final int NOTIFICATION_ID = 1;
|
||||
private NotificationCompat.Builder notificationBuilder;
|
||||
|
||||
private AudioManager audioManager;
|
||||
private MediaPlayer player;
|
||||
|
||||
private FeedMedia media;
|
||||
private Feed feed;
|
||||
/** True if media should be streamed (Extracted from Intent Extra) . */
|
||||
private boolean shouldStream;
|
||||
private boolean startWhenPrepared;
|
||||
private FeedManager manager;
|
||||
private PlayerStatus status;
|
||||
private PositionSaver positionSaver;
|
||||
|
@ -59,9 +85,23 @@ public class PlaybackService extends Service {
|
|||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
isRunning = true;
|
||||
status = PlayerStatus.STOPPED;
|
||||
Log.d(TAG, "Service created.");
|
||||
|
||||
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||
manager = FeedManager.getInstance();
|
||||
player = new MediaPlayer();
|
||||
player.setOnPreparedListener(preparedListener);
|
||||
player.setOnCompletionListener(completionListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
isRunning = false;
|
||||
Log.d(TAG, "Service is about to be destroyed");
|
||||
audioManager.abandonAudioFocus(audioFocusChangeListener);
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -69,10 +109,6 @@ public class PlaybackService extends Service {
|
|||
return mBinder;
|
||||
}
|
||||
|
||||
private void setupAudioManager() {
|
||||
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||
}
|
||||
|
||||
private final OnAudioFocusChangeListener audioFocusChangeListener = new OnAudioFocusChangeListener() {
|
||||
|
||||
@Override
|
||||
|
@ -89,7 +125,8 @@ public class PlaybackService extends Service {
|
|||
break;
|
||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
|
||||
Log.d(TAG, "Lost audio focus temporarily. Ducking...");
|
||||
audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, 0);
|
||||
audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
|
||||
AudioManager.ADJUST_LOWER, 0);
|
||||
break;
|
||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
|
||||
Log.d(TAG, "Lost audio focus temporarily. Pausing...");
|
||||
|
@ -102,21 +139,39 @@ public class PlaybackService extends Service {
|
|||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
long mediaId = intent.getLongExtra(EXTRA_MEDIA_ID, -1);
|
||||
long feedId = intent.getLongExtra(EXTRA_FEED_ID, -1);
|
||||
boolean playbackType = intent
|
||||
.getBooleanExtra(EXTRA_SHOULD_STREAM, true);
|
||||
if (mediaId == -1 || feedId == -1) {
|
||||
Log.e(TAG, "Media ID or Feed ID wasn't provided to the Service.");
|
||||
} else {
|
||||
// Intent values appear to be valid
|
||||
if (audioManager == null) {
|
||||
setupAudioManager();
|
||||
if (media == null || feed == null) {
|
||||
stopSelf();
|
||||
}
|
||||
Feed newFeed = manager.getFeed(feedId);
|
||||
FeedMedia newMedia = manager.getFeedMedia(mediaId, newFeed);
|
||||
if (media != null && media != newMedia) {
|
||||
pause();
|
||||
player.reset();
|
||||
// Intent values appear to be valid
|
||||
// check if already playing and playbackType is the same
|
||||
} else if (media == null || mediaId != media.getId()
|
||||
|| playbackType != shouldStream) {
|
||||
pause();
|
||||
player.reset();
|
||||
if (media == null || mediaId != media.getId()) {
|
||||
feed = manager.getFeed(feedId);
|
||||
media = manager.getFeedMedia(mediaId, feed);
|
||||
}
|
||||
|
||||
if (media != null) {
|
||||
shouldStream = playbackType;
|
||||
startWhenPrepared = intent.getBooleanExtra(
|
||||
EXTRA_START_WHEN_PREPARED, false);
|
||||
try {
|
||||
player.setDataSource(newMedia.getFile_url());
|
||||
player.prepare();
|
||||
if (shouldStream) {
|
||||
player.setDataSource(media.getDownload_url());
|
||||
setStatus(PlayerStatus.PREPARING);
|
||||
player.prepareAsync();
|
||||
} else {
|
||||
player.setDataSource(media.getFile_url());
|
||||
setStatus(PlayerStatus.PREPARING);
|
||||
player.prepare();
|
||||
}
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SecurityException e) {
|
||||
|
@ -126,19 +181,16 @@ public class PlaybackService extends Service {
|
|||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
media = newMedia;
|
||||
feed = newFeed;
|
||||
|
||||
} else if (media == null) {
|
||||
media = newMedia;
|
||||
feed = newFeed;
|
||||
player = MediaPlayer.create(this,
|
||||
Uri.fromFile(new File(media.getFile_url())));
|
||||
setStatus(PlayerStatus.PREPARING);
|
||||
player.setOnPreparedListener(preparedListener);
|
||||
Log.d(TAG, "Preparing to play file");
|
||||
} else {
|
||||
Log.e(TAG, "Media is null");
|
||||
}
|
||||
|
||||
} else if (media != null && status != PlayerStatus.PLAYING) {
|
||||
play();
|
||||
} else {
|
||||
Log.w(TAG, "Something went wrong. Shutting down...");
|
||||
stopSelf();
|
||||
}
|
||||
setupNotification();
|
||||
return Service.START_STICKY;
|
||||
|
@ -168,40 +220,71 @@ public class PlaybackService extends Service {
|
|||
public void onPrepared(MediaPlayer mp) {
|
||||
Log.d(TAG, "Resource prepared");
|
||||
setStatus(PlayerStatus.PREPARED);
|
||||
int focusGained = audioManager.requestAudioFocus(
|
||||
audioFocusChangeListener, AudioManager.STREAM_MUSIC,
|
||||
AudioManager.AUDIOFOCUS_GAIN);
|
||||
if (focusGained == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||
Log.d(TAG, "Audiofocus successfully requested");
|
||||
if (startWhenPrepared) {
|
||||
play();
|
||||
} else {
|
||||
Log.d(TAG, "Failed to request Audiofocus");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private MediaPlayer.OnCompletionListener completionListener = new MediaPlayer.OnCompletionListener() {
|
||||
|
||||
@Override
|
||||
public void onCompletion(MediaPlayer mp) {
|
||||
Log.d(TAG, "Playback completed");
|
||||
positionSaver.cancel(true);
|
||||
media.setPosition(0);
|
||||
manager.markItemRead(PlaybackService.this, media.getItem(), true);
|
||||
if (manager.isInQueue(media.getItem())) {
|
||||
manager.removeQueueItem(PlaybackService.this, media.getItem());
|
||||
}
|
||||
manager.setFeedMedia(PlaybackService.this, media);
|
||||
setStatus(PlayerStatus.STOPPED);
|
||||
stopForeground(true);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
public void pause() {
|
||||
if (player.isPlaying()) {
|
||||
Log.d(TAG, "Pausing playback.");
|
||||
player.pause();
|
||||
saveCurrentPosition();
|
||||
setStatus(PlayerStatus.PAUSED);
|
||||
stopForeground(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void play() {
|
||||
if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED) {
|
||||
Log.d(TAG, "Resuming/Starting playback");
|
||||
player.start();
|
||||
player.seekTo((int) media.getPosition());
|
||||
setStatus(PlayerStatus.PLAYING);
|
||||
setupPositionSaver();
|
||||
} else if (status == PlayerStatus.STOPPED) {
|
||||
if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED
|
||||
|| status == PlayerStatus.STOPPED) {
|
||||
int focusGained = audioManager.requestAudioFocus(
|
||||
audioFocusChangeListener, AudioManager.STREAM_MUSIC,
|
||||
AudioManager.AUDIOFOCUS_GAIN);
|
||||
|
||||
if (focusGained == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||
Log.d(TAG, "Audiofocus successfully requested");
|
||||
|
||||
Log.d(TAG, "Resuming/Starting playback");
|
||||
SharedPreferences.Editor editor = getApplicationContext()
|
||||
.getSharedPreferences(PodcastApp.PREF_NAME, 0).edit();
|
||||
editor.putLong(PREF_LAST_PLAYED_ID, media.getId());
|
||||
editor.putLong(PREF_LAST_PLAYED_FEED_ID, feed.getId());
|
||||
editor.putBoolean(PREF_LAST_IS_STREAM, shouldStream);
|
||||
editor.commit();
|
||||
|
||||
player.start();
|
||||
player.seekTo((int) media.getPosition());
|
||||
setStatus(PlayerStatus.PLAYING);
|
||||
setupPositionSaver();
|
||||
setupNotification();
|
||||
} else {
|
||||
Log.d(TAG, "Failed to request Audiofocus");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setStatus(PlayerStatus newStatus) {
|
||||
Log.d(TAG, "Setting status to " + newStatus);
|
||||
status = newStatus;
|
||||
sendBroadcast(new Intent(ACTION_PLAYER_STATUS_CHANGED));
|
||||
}
|
||||
|
@ -279,4 +362,8 @@ public class PlaybackService extends Service {
|
|||
|
||||
}
|
||||
|
||||
public boolean isShouldStream() {
|
||||
return shouldStream;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ public class FeedItemMenuHandler {
|
|||
menu.findItem(R.id.remove_item).setVisible(true);
|
||||
} else if (selectedItem.getMedia().getFile_url() == null) {
|
||||
menu.findItem(R.id.download_item).setVisible(true);
|
||||
menu.findItem(R.id.stream_item).setVisible(true);
|
||||
} else {
|
||||
menu.findItem(R.id.cancel_download_item).setVisible(true);
|
||||
}
|
||||
|
@ -53,7 +54,7 @@ public class FeedItemMenuHandler {
|
|||
break;
|
||||
case R.id.play_item:
|
||||
manager.playMedia(context,
|
||||
selectedItem.getMedia());
|
||||
selectedItem.getMedia(), true, true, false);
|
||||
break;
|
||||
case R.id.remove_item:
|
||||
manager.deleteFeedMedia(context,
|
||||
|
@ -75,6 +76,8 @@ public class FeedItemMenuHandler {
|
|||
case R.id.remove_from_queue_item:
|
||||
manager.removeQueueItem(context, selectedItem);
|
||||
break;
|
||||
case R.id.stream_item:
|
||||
manager.playMedia(context, selectedItem.getMedia(), true, true, true);
|
||||
}
|
||||
// Refresh menu state
|
||||
|
||||
|
|
Loading…
Reference in New Issue