diff options
Diffstat (limited to 'src/de/danoeh/antennapod/util/playback')
8 files changed, 0 insertions, 1582 deletions
diff --git a/src/de/danoeh/antennapod/util/playback/AudioPlayer.java b/src/de/danoeh/antennapod/util/playback/AudioPlayer.java deleted file mode 100644 index bd49b0d18..000000000 --- a/src/de/danoeh/antennapod/util/playback/AudioPlayer.java +++ /dev/null @@ -1,34 +0,0 @@ -package de.danoeh.antennapod.util.playback; - -import android.content.Context; -import android.util.Log; -import android.view.SurfaceHolder; -import com.aocate.media.MediaPlayer; - -public class AudioPlayer extends MediaPlayer implements IPlayer { - private static final String TAG = "AudioPlayer"; - - public AudioPlayer(Context context) { - super(context); - } - - @Override - public void setScreenOnWhilePlaying(boolean screenOn) { - Log.e(TAG, "Setting screen on while playing not supported in Audio Player"); - throw new UnsupportedOperationException("Setting screen on while playing not supported in Audio Player"); - - } - - @Override - public void setDisplay(SurfaceHolder sh) { - if (sh != null) { - Log.e(TAG, "Setting display not supported in Audio Player"); - throw new UnsupportedOperationException("Setting display not supported in Audio Player"); - } - } - - @Override - public void setVideoScalingMode(int mode) { - throw new UnsupportedOperationException("Setting scaling mode is not supported in Audio Player"); - } -} diff --git a/src/de/danoeh/antennapod/util/playback/ExternalMedia.java b/src/de/danoeh/antennapod/util/playback/ExternalMedia.java deleted file mode 100644 index 3f6e6ae0a..000000000 --- a/src/de/danoeh/antennapod/util/playback/ExternalMedia.java +++ /dev/null @@ -1,237 +0,0 @@ -package de.danoeh.antennapod.util.playback; - -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.media.MediaMetadataRetriever; -import android.net.Uri; -import android.os.Parcel; -import android.os.Parcelable; -import de.danoeh.antennapod.feed.Chapter; -import de.danoeh.antennapod.feed.MediaType; -import de.danoeh.antennapod.util.ChapterUtils; - -import java.io.File; -import java.io.InputStream; -import java.util.List; -import java.util.concurrent.Callable; - -/** Represents a media file that is stored on the local storage device. */ -public class ExternalMedia implements Playable { - - public static final int PLAYABLE_TYPE_EXTERNAL_MEDIA = 2; - public static final String PREF_SOURCE_URL = "ExternalMedia.PrefSourceUrl"; - public static final String PREF_POSITION = "ExternalMedia.PrefPosition"; - public static final String PREF_MEDIA_TYPE = "ExternalMedia.PrefMediaType"; - - private String source; - - private String episodeTitle; - private String feedTitle; - private MediaType mediaType = MediaType.AUDIO; - private List<Chapter> chapters; - private int duration; - private int position; - - public ExternalMedia(String source, MediaType mediaType) { - super(); - this.source = source; - this.mediaType = mediaType; - } - - public ExternalMedia(String source, MediaType mediaType, int position) { - this(source, mediaType); - this.position = position; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(source); - dest.writeString(mediaType.toString()); - dest.writeInt(position); - } - - @Override - public void writeToPreferences(Editor prefEditor) { - prefEditor.putString(PREF_SOURCE_URL, source); - prefEditor.putString(PREF_MEDIA_TYPE, mediaType.toString()); - prefEditor.putInt(PREF_POSITION, position); - } - - @Override - public void loadMetadata() throws PlayableException { - MediaMetadataRetriever mmr = new MediaMetadataRetriever(); - try { - mmr.setDataSource(source); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - throw new PlayableException( - "IllegalArgumentException when setting up MediaMetadataReceiver"); - } catch (RuntimeException e) { - // http://code.google.com/p/android/issues/detail?id=39770 - e.printStackTrace(); - throw new PlayableException( - "RuntimeException when setting up MediaMetadataRetriever"); - } - episodeTitle = mmr - .extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE); - feedTitle = mmr - .extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM); - try { - duration = Integer.parseInt(mmr - .extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)); - } catch (NumberFormatException e) { - e.printStackTrace(); - throw new PlayableException("NumberFormatException when reading duration of media file"); - } - ChapterUtils.loadChaptersFromFileUrl(this); - } - - @Override - public void loadChapterMarks() { - - } - - @Override - public String getEpisodeTitle() { - return episodeTitle; - } - - @Override - public Callable<String> loadShownotes() { - return new Callable<String>() { - @Override - public String call() throws Exception { - return ""; - } - }; - } - - @Override - public List<Chapter> getChapters() { - return chapters; - } - - @Override - public String getWebsiteLink() { - return null; - } - - @Override - public String getPaymentLink() { - return null; - } - - @Override - public String getFeedTitle() { - return feedTitle; - } - - @Override - public Object getIdentifier() { - return source; - } - - @Override - public int getDuration() { - return duration; - } - - @Override - public int getPosition() { - return position; - } - - @Override - public MediaType getMediaType() { - return mediaType; - } - - @Override - public String getLocalMediaUrl() { - return source; - } - - @Override - public String getStreamUrl() { - return null; - } - - @Override - public boolean localFileAvailable() { - return true; - } - - @Override - public boolean streamAvailable() { - return false; - } - - @Override - public void saveCurrentPosition(SharedPreferences pref, int newPosition) { - SharedPreferences.Editor editor = pref.edit(); - editor.putInt(PREF_POSITION, newPosition); - position = newPosition; - editor.commit(); - } - - @Override - public void setPosition(int newPosition) { - position = newPosition; - } - - @Override - public void setDuration(int newDuration) { - duration = newDuration; - } - - @Override - public void onPlaybackStart() { - - } - - @Override - public void onPlaybackCompleted() { - - } - - @Override - public int getPlayableType() { - return PLAYABLE_TYPE_EXTERNAL_MEDIA; - } - - @Override - public void setChapters(List<Chapter> chapters) { - this.chapters = chapters; - } - - public static final Parcelable.Creator<ExternalMedia> CREATOR = new Parcelable.Creator<ExternalMedia>() { - public ExternalMedia createFromParcel(Parcel in) { - String source = in.readString(); - MediaType type = MediaType.valueOf(in.readString()); - int position = 0; - if (in.dataAvail() > 0) { - position = in.readInt(); - } - ExternalMedia extMedia = new ExternalMedia(source, type, position); - return extMedia; - } - - public ExternalMedia[] newArray(int size) { - return new ExternalMedia[size]; - } - }; - - @Override - public Uri getImageUri() { - if (localFileAvailable()) { - return new Uri.Builder().scheme(SCHEME_MEDIA).encodedPath(getLocalMediaUrl()).build(); - } else { - return null; - } - } -} diff --git a/src/de/danoeh/antennapod/util/playback/IPlayer.java b/src/de/danoeh/antennapod/util/playback/IPlayer.java deleted file mode 100644 index 2d4551b13..000000000 --- a/src/de/danoeh/antennapod/util/playback/IPlayer.java +++ /dev/null @@ -1,69 +0,0 @@ -package de.danoeh.antennapod.util.playback; - -import android.content.Context; -import android.view.SurfaceHolder; - -import java.io.IOException; - -public interface IPlayer { - boolean canSetPitch(); - - boolean canSetSpeed(); - - float getCurrentPitchStepsAdjustment(); - - int getCurrentPosition(); - - float getCurrentSpeedMultiplier(); - - int getDuration(); - - float getMaxSpeedMultiplier(); - - float getMinSpeedMultiplier(); - - boolean isLooping(); - - boolean isPlaying(); - - void pause(); - - void prepare() throws IllegalStateException, IOException; - - void prepareAsync(); - - void release(); - - void reset(); - - void seekTo(int msec); - - void setAudioStreamType(int streamtype); - - void setScreenOnWhilePlaying(boolean screenOn); - - void setDataSource(String path) throws IllegalStateException, IOException, - IllegalArgumentException, SecurityException; - - void setDisplay(SurfaceHolder sh); - - void setEnableSpeedAdjustment(boolean enableSpeedAdjustment); - - void setLooping(boolean looping); - - void setPitchStepsAdjustment(float pitchSteps); - - void setPlaybackPitch(float f); - - void setPlaybackSpeed(float f); - - void setVolume(float left, float right); - - void start(); - - void stop(); - - public void setVideoScalingMode(int mode); - - public void setWakeMode(Context context, int mode); -} diff --git a/src/de/danoeh/antennapod/util/playback/MediaPlayerError.java b/src/de/danoeh/antennapod/util/playback/MediaPlayerError.java deleted file mode 100644 index 23ead581f..000000000 --- a/src/de/danoeh/antennapod/util/playback/MediaPlayerError.java +++ /dev/null @@ -1,23 +0,0 @@ -package de.danoeh.antennapod.util.playback; - -import android.content.Context; -import android.media.MediaPlayer; -import de.danoeh.antennapod.R; - -/** Utility class for MediaPlayer errors. */ -public class MediaPlayerError { - - /** Get a human-readable string for a specific error code. */ - public static String getErrorString(Context context, int code) { - int resId; - switch(code) { - case MediaPlayer.MEDIA_ERROR_SERVER_DIED: - resId = R.string.playback_error_server_died; - break; - default: - resId = R.string.playback_error_unknown; - break; - } - return context.getString(resId); - } -} diff --git a/src/de/danoeh/antennapod/util/playback/Playable.java b/src/de/danoeh/antennapod/util/playback/Playable.java deleted file mode 100644 index 004ae56bb..000000000 --- a/src/de/danoeh/antennapod/util/playback/Playable.java +++ /dev/null @@ -1,207 +0,0 @@ -package de.danoeh.antennapod.util.playback; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Parcelable; -import android.util.Log; - -import java.util.List; - -import de.danoeh.antennapod.asynctask.PicassoImageResource; -import de.danoeh.antennapod.feed.Chapter; -import de.danoeh.antennapod.feed.FeedMedia; -import de.danoeh.antennapod.feed.MediaType; -import de.danoeh.antennapod.storage.DBReader; -import de.danoeh.antennapod.util.ShownotesProvider; - -/** - * Interface for objects that can be played by the PlaybackService. - */ -public interface Playable extends Parcelable, - ShownotesProvider, PicassoImageResource { - - /** - * Save information about the playable in a preference so that it can be - * restored later via PlayableUtils.createInstanceFromPreferences. - * Implementations must NOT call commit() after they have written the values - * to the preferences file. - */ - public void writeToPreferences(SharedPreferences.Editor prefEditor); - - /** - * This method is called from a separate thread by the PlaybackService. - * Playable objects should load their metadata in this method. This method - * should execute as quickly as possible and NOT load chapter marks if no - * local file is available. - */ - public void loadMetadata() throws PlayableException; - - /** - * This method is called from a separate thread by the PlaybackService. - * Playable objects should load their chapter marks in this method if no - * local file was available when loadMetadata() was called. - */ - public void loadChapterMarks(); - - /** - * Returns the title of the episode that this playable represents - */ - public String getEpisodeTitle(); - - /** - * Returns a list of chapter marks or null if this Playable has no chapters. - */ - public List<Chapter> getChapters(); - - /** - * Returns a link to a website that is meant to be shown in a browser - */ - public String getWebsiteLink(); - - public String getPaymentLink(); - - /** - * Returns the title of the feed this Playable belongs to. - */ - public String getFeedTitle(); - - /** - * Returns a unique identifier, for example a file url or an ID from a - * database. - */ - public Object getIdentifier(); - - /** - * Return duration of object or 0 if duration is unknown. - */ - public int getDuration(); - - /** - * Return position of object or 0 if position is unknown. - */ - public int getPosition(); - - /** - * Returns the type of media. This method should return the correct value - * BEFORE loadMetadata() is called. - */ - public MediaType getMediaType(); - - /** - * Returns an url to a local file that can be played or null if this file - * does not exist. - */ - public String getLocalMediaUrl(); - - /** - * Returns an url to a file that can be streamed by the player or null if - * this url is not known. - */ - public String getStreamUrl(); - - /** - * Returns true if a local file that can be played is available. getFileUrl - * MUST return a non-null string if this method returns true. - */ - public boolean localFileAvailable(); - - /** - * Returns true if a streamable file is available. getStreamUrl MUST return - * a non-null string if this method returns true. - */ - public boolean streamAvailable(); - - /** - * Saves the current position of this object. Implementations can use the - * provided SharedPreference to save this information and retrieve it later - * via PlayableUtils.createInstanceFromPreferences. - */ - public void saveCurrentPosition(SharedPreferences pref, int newPosition); - - public void setPosition(int newPosition); - - public void setDuration(int newDuration); - - /** - * Is called by the PlaybackService when playback starts. - */ - public void onPlaybackStart(); - - /** - * Is called by the PlaybackService when playback is completed. - */ - public void onPlaybackCompleted(); - - /** - * Returns an integer that must be unique among all Playable classes. The - * return value is later used by PlayableUtils to determine the type of the - * Playable object that is restored. - */ - public int getPlayableType(); - - public void setChapters(List<Chapter> chapters); - - /** - * Provides utility methods for Playable objects. - */ - public static class PlayableUtils { - private static final String TAG = "PlayableUtils"; - - /** - * Restores a playable object from a sharedPreferences file. This method might load data from the database, - * depending on the type of playable that was restored. - * - * @param type An integer that represents the type of the Playable object - * that is restored. - * @param pref The SharedPreferences file from which the Playable object - * is restored - * @return The restored Playable object - */ - public static Playable createInstanceFromPreferences(Context context, int type, - SharedPreferences pref) { - // ADD new Playable types here: - switch (type) { - case FeedMedia.PLAYABLE_TYPE_FEEDMEDIA: - long mediaId = pref.getLong(FeedMedia.PREF_MEDIA_ID, -1); - if (mediaId != -1) { - return DBReader.getFeedMedia(context, mediaId); - } - break; - case ExternalMedia.PLAYABLE_TYPE_EXTERNAL_MEDIA: - String source = pref.getString(ExternalMedia.PREF_SOURCE_URL, - null); - String mediaType = pref.getString( - ExternalMedia.PREF_MEDIA_TYPE, null); - if (source != null && mediaType != null) { - int position = pref.getInt(ExternalMedia.PREF_POSITION, 0); - return new ExternalMedia(source, - MediaType.valueOf(mediaType), position); - } - break; - } - Log.e(TAG, "Could not restore Playable object from preferences"); - return null; - } - } - - public static class PlayableException extends Exception { - private static final long serialVersionUID = 1L; - - public PlayableException() { - super(); - } - - public PlayableException(String detailMessage, Throwable throwable) { - super(detailMessage, throwable); - } - - public PlayableException(String detailMessage) { - super(detailMessage); - } - - public PlayableException(Throwable throwable) { - super(throwable); - } - - } -} diff --git a/src/de/danoeh/antennapod/util/playback/PlaybackController.java b/src/de/danoeh/antennapod/util/playback/PlaybackController.java deleted file mode 100644 index 64dbf4868..000000000 --- a/src/de/danoeh/antennapod/util/playback/PlaybackController.java +++ /dev/null @@ -1,784 +0,0 @@ -package de.danoeh.antennapod.util.playback; - -import android.app.Activity; -import android.content.*; -import android.content.res.TypedArray; -import android.media.MediaPlayer; -import android.os.AsyncTask; -import android.os.IBinder; -import android.preference.PreferenceManager; -import android.util.Log; -import android.util.Pair; -import android.view.SurfaceHolder; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ImageButton; -import android.widget.SeekBar; -import android.widget.TextView; - -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.Validate; - -import de.danoeh.antennapod.BuildConfig; -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.feed.Chapter; -import de.danoeh.antennapod.feed.FeedMedia; -import de.danoeh.antennapod.feed.MediaType; -import de.danoeh.antennapod.preferences.PlaybackPreferences; -import de.danoeh.antennapod.preferences.UserPreferences; -import de.danoeh.antennapod.service.playback.PlaybackService; -import de.danoeh.antennapod.service.playback.PlaybackServiceMediaPlayer; -import de.danoeh.antennapod.service.playback.PlayerStatus; -import de.danoeh.antennapod.storage.DBTasks; -import de.danoeh.antennapod.util.Converter; -import de.danoeh.antennapod.util.playback.Playable.PlayableUtils; - -import java.util.concurrent.*; - -/** - * Communicates with the playback service. GUI classes should use this class to - * control playback instead of communicating with the PlaybackService directly. - */ -public abstract class PlaybackController { - private static final String TAG = "PlaybackController"; - - public static final int INVALID_TIME = -1; - - private final Activity activity; - - private PlaybackService playbackService; - private Playable media; - private PlayerStatus status; - - private ScheduledThreadPoolExecutor schedExecutor; - private static final int SCHED_EX_POOLSIZE = 1; - - protected MediaPositionObserver positionObserver; - protected ScheduledFuture positionObserverFuture; - - private boolean mediaInfoLoaded = false; - private boolean released = false; - - /** - * True if controller should reinit playback service if 'pause' button is - * pressed. - */ - private boolean reinitOnPause; - - public PlaybackController(Activity activity, boolean reinitOnPause) { - Validate.notNull(activity); - - this.activity = activity; - this.reinitOnPause = reinitOnPause; - schedExecutor = new ScheduledThreadPoolExecutor(SCHED_EX_POOLSIZE, - new ThreadFactory() { - - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setPriority(Thread.MIN_PRIORITY); - return t; - } - }, new RejectedExecutionHandler() { - - @Override - public void rejectedExecution(Runnable r, - ThreadPoolExecutor executor) { - Log.w(TAG, - "Rejected execution of runnable in schedExecutor"); - } - } - ); - } - - /** - * Creates a new connection to the playbackService. Should be called in the - * activity's onResume() method. - */ - public void init() { - activity.registerReceiver(statusUpdate, new IntentFilter( - PlaybackService.ACTION_PLAYER_STATUS_CHANGED)); - - activity.registerReceiver(notificationReceiver, new IntentFilter( - PlaybackService.ACTION_PLAYER_NOTIFICATION)); - - activity.registerReceiver(shutdownReceiver, new IntentFilter( - PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)); - - if (!released) { - bindToService(); - } else { - throw new IllegalStateException( - "Can't call init() after release() has been called"); - } - } - - /** - * Should be called if the PlaybackController is no longer needed, for - * example in the activity's onStop() method. - */ - public void release() { - if (BuildConfig.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 - } - - try { - activity.unregisterReceiver(shutdownReceiver); - } catch (IllegalArgumentException e) { - // ignore - } - cancelPositionObserver(); - schedExecutor.shutdownNow(); - media = null; - released = true; - - } - - /** - * Should be called in the activity's onPause() method. - */ - public void pause() { - mediaInfoLoaded = false; - } - - /** - * 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() { - if (BuildConfig.DEBUG) - Log.d(TAG, "Trying to connect to service"); - AsyncTask<Void, Void, Intent> intentLoader = new AsyncTask<Void, Void, Intent>() { - @Override - protected Intent doInBackground(Void... voids) { - return getPlayLastPlayedMediaIntent(); - } - - @Override - protected void onPostExecute(Intent serviceIntent) { - boolean bound = false; - if (!PlaybackService.started) { - if (serviceIntent != null) { - if (BuildConfig.DEBUG) Log.d(TAG, "Calling start service"); - activity.startService(serviceIntent); - bound = activity.bindService(serviceIntent, mConnection, 0); - } else { - status = PlayerStatus.STOPPED; - setupGUI(); - handleStatus(); - } - } else { - if (BuildConfig.DEBUG) - Log.d(TAG, - "PlaybackService is running, trying to connect without start command."); - bound = activity.bindService(new Intent(activity, - PlaybackService.class), mConnection, 0); - } - if (BuildConfig.DEBUG) - Log.d(TAG, "Result for service binding: " + bound); - } - }; - intentLoader.execute(); - } - - /** - * Returns an intent that starts the PlaybackService and plays the last - * played media or null if no last played media could be found. - */ - private Intent getPlayLastPlayedMediaIntent() { - if (BuildConfig.DEBUG) - Log.d(TAG, "Trying to restore last played media"); - SharedPreferences prefs = PreferenceManager - .getDefaultSharedPreferences(activity.getApplicationContext()); - long currentlyPlayingMedia = PlaybackPreferences - .getCurrentlyPlayingMedia(); - if (currentlyPlayingMedia != PlaybackPreferences.NO_MEDIA_PLAYING) { - Playable media = PlayableUtils.createInstanceFromPreferences(activity, - (int) currentlyPlayingMedia, prefs); - if (media != null) { - Intent serviceIntent = new Intent(activity, - PlaybackService.class); - serviceIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media); - serviceIntent.putExtra( - PlaybackService.EXTRA_START_WHEN_PREPARED, false); - serviceIntent.putExtra( - PlaybackService.EXTRA_PREPARE_IMMEDIATELY, false); - boolean fileExists = media.localFileAvailable(); - boolean lastIsStream = PlaybackPreferences - .getCurrentEpisodeIsStream(); - if (!fileExists && !lastIsStream && media instanceof FeedMedia) { - DBTasks.notifyMissingFeedMediaFile( - activity, (FeedMedia) media); - } - serviceIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, - lastIsStream || !fileExists); - return serviceIntent; - } - } - if (BuildConfig.DEBUG) - Log.d(TAG, "No last played media found"); - return null; - } - - public abstract void setupGUI(); - - private void setupPositionObserver() { - if ((positionObserverFuture != null && positionObserverFuture - .isCancelled()) - || (positionObserverFuture != null && positionObserverFuture - .isDone()) || positionObserverFuture == null) { - - if (BuildConfig.DEBUG) - Log.d(TAG, "Setting up position observer"); - positionObserver = new MediaPositionObserver(); - positionObserverFuture = schedExecutor.scheduleWithFixedDelay( - positionObserver, MediaPositionObserver.WAITING_INTERVALL, - MediaPositionObserver.WAITING_INTERVALL, - TimeUnit.MILLISECONDS); - } - } - - private void cancelPositionObserver() { - if (positionObserverFuture != null) { - boolean result = positionObserverFuture.cancel(true); - if (BuildConfig.DEBUG) - Log.d(TAG, "PositionObserver cancelled. Result: " + result); - } - } - - public abstract void onPositionObserverUpdate(); - - private ServiceConnection mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - playbackService = ((PlaybackService.LocalBinder) service) - .getService(); - if (!released) { - queryService(); - if (BuildConfig.DEBUG) - Log.d(TAG, "Connection to Service established"); - } else { - Log.i(TAG, "Connection to playback service has been established, but controller has already been released"); - } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - playbackService = null; - if (BuildConfig.DEBUG) - Log.d(TAG, "Disconnected from Service"); - - } - }; - - protected BroadcastReceiver statusUpdate = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Received statusUpdate Intent."); - if (isConnectedToPlaybackService()) { - PlaybackServiceMediaPlayer.PSMPInfo info = playbackService.getPSMPInfo(); - status = info.playerStatus; - media = info.playable; - handleStatus(); - } else { - Log.w(TAG, - "Couldn't receive status update: playbackService was null"); - bindToService(); - } - } - }; - - protected BroadcastReceiver notificationReceiver = new BroadcastReceiver() { - - @Override - public void onReceive(Context context, Intent intent) { - if (isConnectedToPlaybackService()) { - 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: - cancelPositionObserver(); - mediaInfoLoaded = false; - queryService(); - onReloadNotification(intent.getIntExtra( - PlaybackService.EXTRA_NOTIFICATION_CODE, -1)); - 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; - case PlaybackService.NOTIFICATION_TYPE_PLAYBACK_END: - onPlaybackEnd(); - break; - case PlaybackService.NOTIFICATION_TYPE_PLAYBACK_SPEED_CHANGE: - onPlaybackSpeedChange(); - break; - } - - } else { - if (BuildConfig.DEBUG) - Log.d(TAG, "Bad arguments. Won't handle intent"); - } - } else { - bindToService(); - } - } - - }; - - private BroadcastReceiver shutdownReceiver = new BroadcastReceiver() { - - @Override - public void onReceive(Context context, Intent intent) { - if (isConnectedToPlaybackService()) { - if (StringUtils.equals(intent.getAction(), - PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)) { - release(); - onShutdownNotification(); - } - } - } - }; - - public abstract void onPlaybackSpeedChange(); - - public abstract void onShutdownNotification(); - - /** - * 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); - - public abstract void onPlaybackEnd(); - - /** - * Is called whenever the PlaybackService changes it's status. This method - * should be used to update the GUI or start/cancel background threads. - */ - private void handleStatus() { - final int playResource; - final int pauseResource; - final CharSequence playText = activity.getString(R.string.play_label); - final CharSequence pauseText = activity.getString(R.string.pause_label); - - if (PlaybackService.getCurrentMediaType() == MediaType.AUDIO) { - TypedArray res = activity.obtainStyledAttributes(new int[]{ - R.attr.av_play, R.attr.av_pause}); - playResource = res.getResourceId(0, R.drawable.av_play); - pauseResource = res.getResourceId(1, R.drawable.av_pause); - res.recycle(); - } else { - playResource = R.drawable.ic_action_play_over_video; - pauseResource = R.drawable.ic_action_pause_over_video; - } - - switch (status) { - - case ERROR: - postStatusMsg(R.string.player_error_msg); - handleError(MediaPlayer.MEDIA_ERROR_UNKNOWN); - break; - case PAUSED: - clearStatusMsg(); - checkMediaInfoLoaded(); - cancelPositionObserver(); - updatePlayButtonAppearance(playResource, playText); - if (PlaybackService.getCurrentMediaType() == MediaType.VIDEO) { - setScreenOn(false); - } - break; - case PLAYING: - clearStatusMsg(); - checkMediaInfoLoaded(); - if (PlaybackService.getCurrentMediaType() == MediaType.VIDEO) { - onAwaitingVideoSurface(); - setScreenOn(true); - } - setupPositionObserver(); - updatePlayButtonAppearance(pauseResource, pauseText); - break; - case PREPARING: - postStatusMsg(R.string.player_preparing_msg); - checkMediaInfoLoaded(); - if (playbackService != null) { - if (playbackService.isStartWhenPrepared()) { - updatePlayButtonAppearance(pauseResource, pauseText); - } else { - updatePlayButtonAppearance(playResource, playText); - } - } - break; - case STOPPED: - postStatusMsg(R.string.player_stopped_msg); - break; - case PREPARED: - checkMediaInfoLoaded(); - postStatusMsg(R.string.player_ready_msg); - updatePlayButtonAppearance(playResource, playText); - break; - case SEEKING: - postStatusMsg(R.string.player_seeking_msg); - break; - case INITIALIZED: - checkMediaInfoLoaded(); - clearStatusMsg(); - updatePlayButtonAppearance(playResource, playText); - break; - } - } - - private void checkMediaInfoLoaded() { - mediaInfoLoaded = (mediaInfoLoaded || loadMediaInfo()); - } - - private void updatePlayButtonAppearance(int resource, CharSequence contentDescription) { - ImageButton butPlay = getPlayButton(); - butPlay.setImageResource(resource); - butPlay.setContentDescription(contentDescription); - } - - public abstract ImageButton getPlayButton(); - - public abstract void postStatusMsg(int msg); - - public abstract void clearStatusMsg(); - - public abstract boolean loadMediaInfo(); - - public abstract void onAwaitingVideoSurface(); - - /** - * Called when connection to playback service has been established or - * information has to be refreshed - */ - void queryService() { - if (BuildConfig.DEBUG) - Log.d(TAG, "Querying service info"); - if (playbackService != null) { - status = playbackService.getStatus(); - media = playbackService.getPlayable(); - /* - if (media == null) { - Log.w(TAG, - "PlaybackService has no media object. Trying to restore last played media."); - Intent serviceIntent = getPlayLastPlayedMediaIntent(); - if (serviceIntent != null) { - activity.startService(serviceIntent); - } - } - */ - onServiceQueried(); - - setupGUI(); - handleStatus(); - // make sure that new media is loaded if it's available - mediaInfoLoaded = false; - - } else { - Log.e(TAG, - "queryService() was called without an existing connection to playbackservice"); - } - } - - public abstract void onServiceQueried(); - - /** - * Should be used by classes which implement the OnSeekBarChanged interface. - */ - public float onSeekBarProgressChanged(SeekBar seekBar, int progress, - boolean fromUser, TextView txtvPosition) { - if (fromUser && playbackService != null && media != null) { - float prog = progress / ((float) seekBar.getMax()); - int duration = media.getDuration(); - txtvPosition.setText(Converter - .getDurationStringLong((int) (prog * duration))); - return prog; - } - return 0; - - } - - /** - * Should be used by classes which implement the OnSeekBarChanged interface. - */ - public void onSeekBarStartTrackingTouch(SeekBar seekBar) { - // interrupt position Observer, restart later - cancelPositionObserver(); - } - - /** - * Should be used by classes which implement the OnSeekBarChanged interface. - */ - public void onSeekBarStopTrackingTouch(SeekBar seekBar, float prog) { - if (playbackService != null) { - playbackService.seekTo((int) (prog * media.getDuration())); - setupPositionObserver(); - } - } - - /** - * Should be implemented by classes that show a video. The default implementation - * does nothing - * - * @param enable True if the screen should be kept on, false otherwise - */ - protected void setScreenOn(boolean enable) { - - } - - public OnClickListener newOnPlayButtonClickListener() { - return new OnClickListener() { - @Override - public void onClick(View v) { - if (playbackService != null) { - switch (status) { - case PLAYING: - playbackService.pause(true, reinitOnPause); - break; - case PAUSED: - case PREPARED: - playbackService.resume(); - break; - case PREPARING: - playbackService.setStartWhenPrepared(!playbackService - .isStartWhenPrepared()); - if (reinitOnPause - && playbackService.isStartWhenPrepared() == false) { - playbackService.reinit(); - } - break; - case INITIALIZED: - playbackService.setStartWhenPrepared(true); - playbackService.prepare(); - break; - } - } 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(-UserPreferences.getSeekDeltaMs()); - } - } - }; - } - - public OnClickListener newOnFFButtonClickListener() { - return new OnClickListener() { - @Override - public void onClick(View v) { - if (status == PlayerStatus.PLAYING) { - playbackService.seekDelta(UserPreferences.getSeekDeltaMs()); - } - } - }; - } - - public boolean serviceAvailable() { - return playbackService != null; - } - - public int getPosition() { - if (playbackService != null) { - return playbackService.getCurrentPosition(); - } else { - return PlaybackService.INVALID_TIME; - } - } - - public int getDuration() { - if (playbackService != null) { - return playbackService.getDuration(); - } else { - return PlaybackService.INVALID_TIME; - } - } - - public Playable 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(Chapter chapter) { - if (playbackService != null) { - playbackService.seekToChapter(chapter); - } - } - - public void seekTo(int time) { - if (playbackService != null) { - playbackService.seekTo(time); - } - } - - public void setVideoSurface(SurfaceHolder holder) { - if (playbackService != null) { - playbackService.setVideoSurface(holder); - } - } - - public PlayerStatus getStatus() { - return status; - } - - public boolean canSetPlaybackSpeed() { - return playbackService != null && playbackService.canSetSpeed(); - } - - public void setPlaybackSpeed(float speed) { - if (playbackService != null) { - playbackService.setSpeed(speed); - } - } - - public float getCurrentPlaybackSpeedMultiplier() { - if (canSetPlaybackSpeed()) { - return playbackService.getCurrentPlaybackSpeed(); - } else { - return -1; - } - } - - public boolean isPlayingVideo() { - if (playbackService != null) { - return PlaybackService.getCurrentMediaType() == MediaType.VIDEO; - } - return false; - } - - public Pair<Integer, Integer> getVideoSize() { - if (playbackService != null) { - return playbackService.getVideoSize(); - } else { - return null; - } - } - - - /** - * Returns true if PlaybackController can communicate with the playback - * service. - */ - public boolean isConnectedToPlaybackService() { - return playbackService != null; - } - - public void notifyVideoSurfaceAbandoned() { - if (playbackService != null) { - playbackService.notifyVideoSurfaceAbandoned(); - } - } - - /** - * Move service into INITIALIZED state if it's paused to save bandwidth - */ - public void reinitServiceIfPaused() { - if (playbackService != null - && playbackService.isStreaming() - && (playbackService.getStatus() == PlayerStatus.PAUSED || (playbackService - .getStatus() == PlayerStatus.PREPARING && playbackService - .isStartWhenPrepared() == false))) { - playbackService.reinit(); - } - } - - /** - * Refreshes the current position of the media file that is playing. - */ - public class MediaPositionObserver implements Runnable { - - public static final int WAITING_INTERVALL = 1000; - - @Override - public void run() { - if (playbackService != null && playbackService.getStatus() == PlayerStatus.PLAYING) { - activity.runOnUiThread(new Runnable() { - - @Override - public void run() { - onPositionObserverUpdate(); - } - }); - } - } - } -} diff --git a/src/de/danoeh/antennapod/util/playback/Timeline.java b/src/de/danoeh/antennapod/util/playback/Timeline.java deleted file mode 100644 index ceed68183..000000000 --- a/src/de/danoeh/antennapod/util/playback/Timeline.java +++ /dev/null @@ -1,161 +0,0 @@ -package de.danoeh.antennapod.util.playback; - -import android.content.Context; -import android.content.res.TypedArray; -import android.util.Log; -import android.util.TypedValue; - -import org.apache.commons.lang3.Validate; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import de.danoeh.antennapod.BuildConfig; -import de.danoeh.antennapod.util.Converter; -import de.danoeh.antennapod.util.ShownotesProvider; - -/** - * Connects chapter information and shownotes of a shownotesProvider, for example by making it possible to use the - * shownotes to navigate to another position in the podcast or by highlighting certain parts of the shownotesProvider's - * shownotes. - * <p/> - * A timeline object needs a shownotesProvider from which the chapter information is retrieved and shownotes are generated. - */ -public class Timeline { - private static final String TAG = "Timeline"; - - private static final String WEBVIEW_STYLE = "@font-face { font-family: 'Roboto-Light'; src: url('file:///android_asset/Roboto-Light.ttf'); } * { color: %s; font-family: roboto-Light; font-size: 11pt; } a { font-style: normal; text-decoration: none; font-weight: normal; color: #00A8DF; } a.timecode { color: #669900; } img { display: block; margin: 10 auto; max-width: %s; height: auto; } body { margin: %dpx %dpx %dpx %dpx; }"; - - - private ShownotesProvider shownotesProvider; - - - private final String colorString; - private final int pageMargin; - - public Timeline(Context context, ShownotesProvider shownotesProvider) { - if (shownotesProvider == null) throw new IllegalArgumentException("shownotesProvider = null"); - this.shownotesProvider = shownotesProvider; - - TypedArray res = context - .getTheme() - .obtainStyledAttributes( - new int[]{android.R.attr.textColorPrimary}); - int colorResource = res.getColor(0, 0); - colorString = String.format("#%06X", - 0xFFFFFF & colorResource); - res.recycle(); - - pageMargin = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, 8, context.getResources() - .getDisplayMetrics() - ); - } - - private static final Pattern TIMECODE_LINK_REGEX = Pattern.compile("antennapod://timecode/((\\d+))"); - private static final String TIMECODE_LINK = "<a class=\"timecode\" href=\"antennapod://timecode/%d\">%s</a>"; - private static final Pattern TIMECODE_REGEX = Pattern.compile("\\b(?:(?:(([0-9][0-9])):))?(([0-9][0-9])):(([0-9][0-9]))\\b"); - - /** - * Applies an app-specific CSS stylesheet and adds timecode links (optional). - * <p/> - * This method does NOT change the original shownotes string of the shownotesProvider object and it should - * also not be changed by the caller. - * - * @param addTimecodes True if this method should add timecode links - * @return The processed HTML string. - */ - public String processShownotes(final boolean addTimecodes) { - final Playable playable = (shownotesProvider instanceof Playable) ? (Playable) shownotesProvider : null; - - // load shownotes - - String shownotes; - try { - shownotes = shownotesProvider.loadShownotes().call(); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - if (shownotes == null) { - if (BuildConfig.DEBUG) - Log.d(TAG, "shownotesProvider contained no shownotes. Returning empty string"); - return ""; - } - - Document document = Jsoup.parse(shownotes); - - // apply style - String styleStr = String.format(WEBVIEW_STYLE, colorString, "100%", pageMargin, - pageMargin, pageMargin, pageMargin); - document.head().appendElement("style").attr("type", "text/css").text(styleStr); - - // apply timecode links - if (addTimecodes) { - Elements elementsWithTimeCodes = document.body().getElementsMatchingOwnText(TIMECODE_REGEX); - if (BuildConfig.DEBUG) - Log.d(TAG, "Recognized " + elementsWithTimeCodes.size() + " timecodes"); - for (Element element : elementsWithTimeCodes) { - Matcher matcherLong = TIMECODE_REGEX.matcher(element.text()); - StringBuffer buffer = new StringBuffer(); - while (matcherLong.find()) { - String h = matcherLong.group(1); - String group = matcherLong.group(0); - int time = (h != null) ? Converter.durationStringLongToMs(group) : - Converter.durationStringShortToMs(group); - - String rep; - if (playable == null || playable.getDuration() > time) { - rep = String.format(TIMECODE_LINK, time, group); - } else { - rep = group; - } - matcherLong.appendReplacement(buffer, rep); - } - matcherLong.appendTail(buffer); - - element.html(buffer.toString()); - } - } - - Log.i(TAG, "Out: " + document.toString()); - return document.toString(); - } - - - /** - * Returns true if the given link is a timecode link. - */ - public static boolean isTimecodeLink(String link) { - return link != null && link.matches(TIMECODE_LINK_REGEX.pattern()); - } - - /** - * Returns the time in milliseconds that is attached to this link or -1 - * if the link is no valid timecode link. - */ - public static int getTimecodeLinkTime(String link) { - if (isTimecodeLink(link)) { - Matcher m = TIMECODE_LINK_REGEX.matcher(link); - - try { - if (m.find()) { - return Integer.valueOf(m.group(1)); - } - } catch (NumberFormatException e) { - e.printStackTrace(); - } - } - return -1; - } - - - public void setShownotesProvider(ShownotesProvider shownotesProvider) { - Validate.notNull(shownotesProvider); - this.shownotesProvider = shownotesProvider; - } -} diff --git a/src/de/danoeh/antennapod/util/playback/VideoPlayer.java b/src/de/danoeh/antennapod/util/playback/VideoPlayer.java deleted file mode 100644 index ea9c692ab..000000000 --- a/src/de/danoeh/antennapod/util/playback/VideoPlayer.java +++ /dev/null @@ -1,67 +0,0 @@ -package de.danoeh.antennapod.util.playback; - -import android.media.MediaPlayer; -import android.util.Log; - -public class VideoPlayer extends MediaPlayer implements IPlayer { - private static final String TAG = "VideoPlayer"; - - @Override - public boolean canSetPitch() { - return false; - } - - @Override - public boolean canSetSpeed() { - return false; - } - - @Override - public float getCurrentPitchStepsAdjustment() { - return 1; - } - - @Override - public float getCurrentSpeedMultiplier() { - return 1; - } - - @Override - public float getMaxSpeedMultiplier() { - return 1; - } - - @Override - public float getMinSpeedMultiplier() { - return 1; - } - - @Override - public void setEnableSpeedAdjustment(boolean enableSpeedAdjustment) throws UnsupportedOperationException { - Log.e(TAG, "Setting enable speed adjustment unsupported in video player"); - throw new UnsupportedOperationException("Setting enable speed adjustment unsupported in video player"); - } - - @Override - public void setPitchStepsAdjustment(float pitchSteps) { - Log.e(TAG, "Setting pitch steps adjustment unsupported in video player"); - throw new UnsupportedOperationException("Setting pitch steps adjustment unsupported in video player"); - } - - @Override - public void setPlaybackPitch(float f) { - Log.e(TAG, "Setting playback pitch unsupported in video player"); - throw new UnsupportedOperationException("Setting playback pitch unsupported in video player"); - } - - @Override - public void setPlaybackSpeed(float f) { - Log.e(TAG, "Setting playback speed unsupported in video player"); - throw new UnsupportedOperationException("Setting playback speed unsupported in video player"); - } - - @Override - public void setVideoScalingMode(int mode) { - super.setVideoScalingMode(mode); - } -} |