From 817769672a1340dbdeb26066d57215b2a2642423 Mon Sep 17 00:00:00 2001 From: David Reiss Date: Sat, 7 Jun 2014 16:26:38 -0700 Subject: Remove unnecessary braces in PlaybackService case block The other blocks in this switch don't have braces, and they would look a little silly when I add an extra case label. --- src/de/danoeh/antennapod/service/playback/PlaybackService.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/de/danoeh/antennapod') diff --git a/src/de/danoeh/antennapod/service/playback/PlaybackService.java b/src/de/danoeh/antennapod/service/playback/PlaybackService.java index b7ff62129..1c0a15860 100644 --- a/src/de/danoeh/antennapod/service/playback/PlaybackService.java +++ b/src/de/danoeh/antennapod/service/playback/PlaybackService.java @@ -310,14 +310,12 @@ public class PlaybackService extends Service { mediaPlayer.pause(true, true); } break; - case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: mediaPlayer.seekDelta(PlaybackController.DEFAULT_SEEK_DELTA); break; - } - case KeyEvent.KEYCODE_MEDIA_REWIND: { + case KeyEvent.KEYCODE_MEDIA_REWIND: mediaPlayer.seekDelta(-PlaybackController.DEFAULT_SEEK_DELTA); break; - } } } -- cgit v1.2.3 From 12660478a8249e55bd24d3503504dcf6b25482b3 Mon Sep 17 00:00:00 2001 From: David Reiss Date: Sat, 7 Jun 2014 16:23:34 -0700 Subject: Support next/previous media keys The "seek" buttons in my car send "next" and "previous" media key codes, rather than "fast forward" and "rewind", so update the playback service to recognize them. fixes #386 fixes #432 --- src/de/danoeh/antennapod/service/playback/PlaybackService.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/de/danoeh/antennapod') diff --git a/src/de/danoeh/antennapod/service/playback/PlaybackService.java b/src/de/danoeh/antennapod/service/playback/PlaybackService.java index 1c0a15860..0eb873f6f 100644 --- a/src/de/danoeh/antennapod/service/playback/PlaybackService.java +++ b/src/de/danoeh/antennapod/service/playback/PlaybackService.java @@ -310,9 +310,11 @@ public class PlaybackService extends Service { mediaPlayer.pause(true, true); } break; + case KeyEvent.KEYCODE_MEDIA_NEXT: case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: mediaPlayer.seekDelta(PlaybackController.DEFAULT_SEEK_DELTA); break; + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: case KeyEvent.KEYCODE_MEDIA_REWIND: mediaPlayer.seekDelta(-PlaybackController.DEFAULT_SEEK_DELTA); break; -- cgit v1.2.3 From a78c5173dccfe76cb2e4886e83a6a5b040375700 Mon Sep 17 00:00:00 2001 From: David Reiss Date: Sat, 7 Jun 2014 16:24:03 -0700 Subject: Show a toast when an unknown media key is pressed This is just an idea. If people want more media keys supported, they will be able to use this toast to report exactly what key codes their hardware is generating. If you don't want to include this, just let me know and I can remove it from the pull request. --- src/de/danoeh/antennapod/service/playback/PlaybackService.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/de/danoeh/antennapod') diff --git a/src/de/danoeh/antennapod/service/playback/PlaybackService.java b/src/de/danoeh/antennapod/service/playback/PlaybackService.java index 0eb873f6f..1165a977e 100644 --- a/src/de/danoeh/antennapod/service/playback/PlaybackService.java +++ b/src/de/danoeh/antennapod/service/playback/PlaybackService.java @@ -22,6 +22,7 @@ import android.util.Log; import android.util.Pair; import android.view.KeyEvent; import android.view.SurfaceHolder; +import android.widget.Toast; import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.R; @@ -318,6 +319,10 @@ public class PlaybackService extends Service { case KeyEvent.KEYCODE_MEDIA_REWIND: mediaPlayer.seekDelta(-PlaybackController.DEFAULT_SEEK_DELTA); break; + default: + String message = String.format(getResources().getString(R.string.unknown_media_key), keycode); + Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); + break; } } -- cgit v1.2.3 From 500483ba690a36365dda1f6e00bb9c50c6357248 Mon Sep 17 00:00:00 2001 From: David Reiss Date: Sat, 7 Jun 2014 14:13:07 -0700 Subject: Make seek time configurable A 30-second seek time is way to long for me. Make the seek duration a configurable preference. --- src/de/danoeh/antennapod/preferences/UserPreferences.java | 10 ++++++++++ src/de/danoeh/antennapod/service/playback/PlaybackService.java | 5 ++--- src/de/danoeh/antennapod/util/playback/PlaybackController.java | 6 +++--- 3 files changed, 15 insertions(+), 6 deletions(-) (limited to 'src/de/danoeh/antennapod') diff --git a/src/de/danoeh/antennapod/preferences/UserPreferences.java b/src/de/danoeh/antennapod/preferences/UserPreferences.java index 31250bcd9..bb10e46d1 100644 --- a/src/de/danoeh/antennapod/preferences/UserPreferences.java +++ b/src/de/danoeh/antennapod/preferences/UserPreferences.java @@ -48,6 +48,7 @@ public class UserPreferences implements private static final String PREF_PLAYBACK_SPEED = "prefPlaybackSpeed"; private static final String PREF_PLAYBACK_SPEED_ARRAY = "prefPlaybackSpeedArray"; public static final String PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS = "prefPauseForFocusLoss"; + private static final String PREF_SEEK_DELTA_SECS = "prefSeekDeltaSecs"; // TODO: Make this value configurable private static final double PLAYED_DURATION_AUTOFLATTR_THRESHOLD = 0.8; @@ -74,6 +75,7 @@ public class UserPreferences implements private String playbackSpeed; private String[] playbackSpeedArray; private boolean pauseForFocusLoss; + private int seekDeltaSecs; private boolean isFreshInstall; private UserPreferences(Context context) { @@ -129,6 +131,7 @@ public class UserPreferences implements playbackSpeedArray = readPlaybackSpeedArray(sp.getString( PREF_PLAYBACK_SPEED_ARRAY, null)); pauseForFocusLoss = sp.getBoolean(PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, false); + seekDeltaSecs = Integer.valueOf(sp.getString(PREF_SEEK_DELTA_SECS, "30")); } private int readThemeValue(String valueFromPrefs) { @@ -263,6 +266,11 @@ public class UserPreferences implements return instance.playbackSpeedArray; } + public static int getSeekDeltaMs() { + instanceAvailable(); + return 1000 * instance.seekDeltaSecs; + } + /** * Returns the capacity of the episode cache. This method will return the * negative integer EPISODE_CACHE_SIZE_UNLIMITED if the cache size is set to @@ -336,6 +344,8 @@ public class UserPreferences implements PREF_PLAYBACK_SPEED_ARRAY, null)); } else if (key.equals(PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS)) { pauseForFocusLoss = sp.getBoolean(PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, false); + } else if (key.equals(PREF_SEEK_DELTA_SECS)) { + seekDeltaSecs = Integer.valueOf(sp.getString(PREF_SEEK_DELTA_SECS, "30")); } else if (key.equals(PREF_PAUSE_ON_HEADSET_DISCONNECT)) { pauseOnHeadsetDisconnect = sp.getBoolean(PREF_PAUSE_ON_HEADSET_DISCONNECT, true); } diff --git a/src/de/danoeh/antennapod/service/playback/PlaybackService.java b/src/de/danoeh/antennapod/service/playback/PlaybackService.java index 1165a977e..04b41ca81 100644 --- a/src/de/danoeh/antennapod/service/playback/PlaybackService.java +++ b/src/de/danoeh/antennapod/service/playback/PlaybackService.java @@ -42,7 +42,6 @@ import de.danoeh.antennapod.util.BitmapDecoder; import de.danoeh.antennapod.util.QueueAccess; import de.danoeh.antennapod.util.flattr.FlattrUtils; import de.danoeh.antennapod.util.playback.Playable; -import de.danoeh.antennapod.util.playback.PlaybackController; import java.util.List; @@ -313,11 +312,11 @@ public class PlaybackService extends Service { break; case KeyEvent.KEYCODE_MEDIA_NEXT: case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: - mediaPlayer.seekDelta(PlaybackController.DEFAULT_SEEK_DELTA); + mediaPlayer.seekDelta(UserPreferences.getSeekDeltaMs()); break; case KeyEvent.KEYCODE_MEDIA_PREVIOUS: case KeyEvent.KEYCODE_MEDIA_REWIND: - mediaPlayer.seekDelta(-PlaybackController.DEFAULT_SEEK_DELTA); + mediaPlayer.seekDelta(-UserPreferences.getSeekDeltaMs()); break; default: String message = String.format(getResources().getString(R.string.unknown_media_key), keycode); diff --git a/src/de/danoeh/antennapod/util/playback/PlaybackController.java b/src/de/danoeh/antennapod/util/playback/PlaybackController.java index 1992fce2c..5783b5bc5 100644 --- a/src/de/danoeh/antennapod/util/playback/PlaybackController.java +++ b/src/de/danoeh/antennapod/util/playback/PlaybackController.java @@ -21,6 +21,7 @@ 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; @@ -37,7 +38,6 @@ import java.util.concurrent.*; public abstract class PlaybackController { private static final String TAG = "PlaybackController"; - public static final int DEFAULT_SEEK_DELTA = 30000; public static final int INVALID_TIME = -1; private final Activity activity; @@ -605,7 +605,7 @@ public abstract class PlaybackController { @Override public void onClick(View v) { if (status == PlayerStatus.PLAYING) { - playbackService.seekDelta(-DEFAULT_SEEK_DELTA); + playbackService.seekDelta(-UserPreferences.getSeekDeltaMs()); } } }; @@ -616,7 +616,7 @@ public abstract class PlaybackController { @Override public void onClick(View v) { if (status == PlayerStatus.PLAYING) { - playbackService.seekDelta(DEFAULT_SEEK_DELTA); + playbackService.seekDelta(UserPreferences.getSeekDeltaMs()); } } }; -- cgit v1.2.3 From 45646d4c26bd23aa84948fa120efd464efcceec9 Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Sun, 15 Jun 2014 18:22:15 +0200 Subject: Only report unknown keycode if PlaybackService is playing --- src/de/danoeh/antennapod/service/playback/PlaybackService.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/de/danoeh/antennapod') diff --git a/src/de/danoeh/antennapod/service/playback/PlaybackService.java b/src/de/danoeh/antennapod/service/playback/PlaybackService.java index 04b41ca81..4ecf5db8a 100644 --- a/src/de/danoeh/antennapod/service/playback/PlaybackService.java +++ b/src/de/danoeh/antennapod/service/playback/PlaybackService.java @@ -282,7 +282,8 @@ public class PlaybackService extends Service { if (BuildConfig.DEBUG) Log.d(TAG, "Handling keycode: " + keycode); - final PlayerStatus status = mediaPlayer.getPSMPInfo().playerStatus; + final PlaybackServiceMediaPlayer.PSMPInfo info = mediaPlayer.getPSMPInfo(); + final PlayerStatus status = info.playerStatus; switch (keycode) { case KeyEvent.KEYCODE_HEADSETHOOK: case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: @@ -319,8 +320,10 @@ public class PlaybackService extends Service { mediaPlayer.seekDelta(-UserPreferences.getSeekDeltaMs()); break; default: - String message = String.format(getResources().getString(R.string.unknown_media_key), keycode); - Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); + if (info.playable != null && info.playerStatus == PlayerStatus.PLAYING) { // only notify the user about an unknown key event if it is actually doing something + String message = String.format(getResources().getString(R.string.unknown_media_key), keycode); + Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); + } break; } } -- cgit v1.2.3 From 5ede220e639d3202b515cf29df28bc4c52d170bf Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Sun, 15 Jun 2014 20:21:31 +0200 Subject: Replaced TimerDialog with HmsDialog from the BetterPickers-library --- .../antennapod/activity/MediaplayerActivity.java | 44 +++++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) (limited to 'src/de/danoeh/antennapod') diff --git a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java index fc70f4c05..c2d8d2c79 100644 --- a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java +++ b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java @@ -3,10 +3,13 @@ package de.danoeh.antennapod.activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; +import android.content.res.TypedArray; import android.graphics.PixelFormat; import android.media.AudioManager; import android.net.Uri; +import android.os.Build; import android.os.Bundle; +import android.support.v4.app.DialogFragment; import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.view.Menu; @@ -16,6 +19,8 @@ import android.widget.ImageButton; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; +import com.doomonafireball.betterpickers.hmspicker.HmsPickerBuilder; +import com.doomonafireball.betterpickers.hmspicker.HmsPickerDialogFragment; import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.dialog.TimeDialog; @@ -30,6 +35,7 @@ import de.danoeh.antennapod.util.StorageUtils; import de.danoeh.antennapod.util.playback.MediaPlayerError; import de.danoeh.antennapod.util.playback.Playable; import de.danoeh.antennapod.util.playback.PlaybackController; +import org.shredzone.flattr4j.model.User; /** * Provides general features which are both needed for playing audio and video @@ -312,16 +318,34 @@ public abstract class MediaplayerActivity extends ActionBarActivity break; case R.id.set_sleeptimer_item: if (controller.serviceAvailable()) { - TimeDialog td = new TimeDialog(this, - R.string.set_sleeptimer_label, - R.string.set_sleeptimer_label) { - - @Override - public void onTimeEntered(long millis) { - controller.setSleepTimer(millis); - } - }; - td.show(); + int pickerStyle = (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Light) ? + R.style.AntennaPodBetterPickerThemeLight : R.style.AntennaPodBetterPickerThemeDark; + if (Build.VERSION.SDK_INT > 10) { // TODO remove this as soon as dialog is shown correctly on 2.3 + HmsPickerBuilder hpb = new HmsPickerBuilder() + .setStyleResId(pickerStyle) + .setFragmentManager(getSupportFragmentManager()); + + hpb.addHmsPickerDialogHandler(new HmsPickerDialogFragment.HmsPickerDialogHandler() { + @Override + public void onDialogHmsSet(int ref, int hours, int minutes, int seconds) { + if (controller != null && controller.serviceAvailable()) { + controller.setSleepTimer((hours * 3600 + minutes * 60 + seconds) * 1000); + } + } + }); + hpb.show(); + } else { + TimeDialog td = new TimeDialog(this, + R.string.set_sleeptimer_label, + R.string.set_sleeptimer_label) { + + @Override + public void onTimeEntered(long millis) { + controller.setSleepTimer(millis); + } + }; + td.show(); + } break; } -- cgit v1.2.3 From 8a951d0dbf220e2c7b26b18d6dbc1de4ed5cf718 Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Sun, 15 Jun 2014 20:35:50 +0200 Subject: Show keyboard when opening TimeDialog. fixes #436 --- src/de/danoeh/antennapod/dialog/TimeDialog.java | 214 +++++++++++++----------- 1 file changed, 112 insertions(+), 102 deletions(-) (limited to 'src/de/danoeh/antennapod') diff --git a/src/de/danoeh/antennapod/dialog/TimeDialog.java b/src/de/danoeh/antennapod/dialog/TimeDialog.java index cb3ebf0ab..bbd514640 100644 --- a/src/de/danoeh/antennapod/dialog/TimeDialog.java +++ b/src/de/danoeh/antennapod/dialog/TimeDialog.java @@ -8,6 +8,7 @@ import android.text.TextWatcher; import android.util.Log; import android.view.View; import android.view.Window; +import android.view.inputmethod.InputMethodManager; import android.widget.*; import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; @@ -15,114 +16,123 @@ import de.danoeh.antennapod.R; import java.util.concurrent.TimeUnit; public abstract class TimeDialog extends Dialog { - private static final String TAG = "TimeDialog"; + private static final String TAG = "TimeDialog"; - private static final int DEFAULT_SPINNER_POSITION = 1; + private static final int DEFAULT_SPINNER_POSITION = 1; - private Context context; + private Context context; - private EditText etxtTime; - private Spinner spTimeUnit; - private Button butConfirm; - private Button butCancel; + private EditText etxtTime; + private Spinner spTimeUnit; + private Button butConfirm; + private Button butCancel; - private TimeUnit[] units = { TimeUnit.SECONDS, TimeUnit.MINUTES, - TimeUnit.HOURS }; + private TimeUnit[] units = {TimeUnit.SECONDS, TimeUnit.MINUTES, + TimeUnit.HOURS}; - public TimeDialog(Context context, int titleTextId, int leftButtonTextId) { - super(context); - this.context = context; - } + public TimeDialog(Context context, int titleTextId, int leftButtonTextId) { + super(context); + this.context = context; + } - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - requestWindowFeature(Window.FEATURE_NO_TITLE); + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + requestWindowFeature(Window.FEATURE_NO_TITLE); String[] spinnerContent = new String[]{context.getString(R.string.time_unit_seconds), - context.getString(R.string.time_unit_minutes), - context.getString(R.string.time_unit_hours)}; - - setContentView(R.layout.time_dialog); - etxtTime = (EditText) findViewById(R.id.etxtTime); - spTimeUnit = (Spinner) findViewById(R.id.spTimeUnit); - butConfirm = (Button) findViewById(R.id.butConfirm); - butCancel = (Button) findViewById(R.id.butCancel); - - butConfirm.setText(R.string.set_sleeptimer_label); - butCancel.setText(R.string.cancel_label); - setTitle(R.string.set_sleeptimer_label); - ArrayAdapter spinnerAdapter = new ArrayAdapter( - this.getContext(), android.R.layout.simple_spinner_item, - spinnerContent); - spinnerAdapter - .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - spTimeUnit.setAdapter(spinnerAdapter); - spTimeUnit.setSelection(DEFAULT_SPINNER_POSITION); - butCancel.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - dismiss(); - } - }); - butConfirm.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - try { - long input = readTimeMillis(); - onTimeEntered(input); - dismiss(); - } catch (NumberFormatException e) { - e.printStackTrace(); - Toast toast = Toast.makeText(context, - R.string.time_dialog_invalid_input, - Toast.LENGTH_LONG); - toast.show(); - } - } - }); - etxtTime.addTextChangedListener(new TextWatcher() { - - @Override - public void afterTextChanged(Editable s) { - checkInputLength(s.length()); - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - - } - }); - checkInputLength(etxtTime.getText().length()); - - } - - private void checkInputLength(int length) { - if (length > 0) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Length is larger than 0, enabling confirm button"); - butConfirm.setEnabled(true); - } else { - if (BuildConfig.DEBUG) - Log.d(TAG, "Length is smaller than 0, disabling confirm button"); - butConfirm.setEnabled(false); - } - } - - public abstract void onTimeEntered(long millis); - - private long readTimeMillis() { - TimeUnit selectedUnit = units[spTimeUnit.getSelectedItemPosition()]; - long value = Long.valueOf(etxtTime.getText().toString()); - return selectedUnit.toMillis(value); - } + context.getString(R.string.time_unit_minutes), + context.getString(R.string.time_unit_hours)}; + + setContentView(R.layout.time_dialog); + etxtTime = (EditText) findViewById(R.id.etxtTime); + spTimeUnit = (Spinner) findViewById(R.id.spTimeUnit); + butConfirm = (Button) findViewById(R.id.butConfirm); + butCancel = (Button) findViewById(R.id.butCancel); + + butConfirm.setText(R.string.set_sleeptimer_label); + butCancel.setText(R.string.cancel_label); + setTitle(R.string.set_sleeptimer_label); + ArrayAdapter spinnerAdapter = new ArrayAdapter( + this.getContext(), android.R.layout.simple_spinner_item, + spinnerContent); + spinnerAdapter + .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spTimeUnit.setAdapter(spinnerAdapter); + spTimeUnit.setSelection(DEFAULT_SPINNER_POSITION); + butCancel.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + dismiss(); + } + }); + butConfirm.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + try { + long input = readTimeMillis(); + onTimeEntered(input); + dismiss(); + } catch (NumberFormatException e) { + e.printStackTrace(); + Toast toast = Toast.makeText(context, + R.string.time_dialog_invalid_input, + Toast.LENGTH_LONG); + toast.show(); + } + } + }); + etxtTime.addTextChangedListener(new TextWatcher() { + + @Override + public void afterTextChanged(Editable s) { + checkInputLength(s.length()); + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + + } + }); + checkInputLength(etxtTime.getText().length()); + etxtTime.postDelayed(new Runnable() { + @Override + public void run() { + InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(etxtTime, InputMethodManager.SHOW_IMPLICIT); + } + }, 100); + + + + } + + private void checkInputLength(int length) { + if (length > 0) { + if (BuildConfig.DEBUG) + Log.d(TAG, "Length is larger than 0, enabling confirm button"); + butConfirm.setEnabled(true); + } else { + if (BuildConfig.DEBUG) + Log.d(TAG, "Length is smaller than 0, disabling confirm button"); + butConfirm.setEnabled(false); + } + } + + public abstract void onTimeEntered(long millis); + + private long readTimeMillis() { + TimeUnit selectedUnit = units[spTimeUnit.getSelectedItemPosition()]; + long value = Long.valueOf(etxtTime.getText().toString()); + return selectedUnit.toMillis(value); + } } -- cgit v1.2.3 From a2757866402f01c6683d0ba17cf19e3e7d158fbe Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Sun, 15 Jun 2014 21:02:35 +0200 Subject: Remove HTML markup in OnlineFeedView. closes #401 --- .../activity/DefaultOnlineFeedViewActivity.java | 29 ++++++++++++++++++++-- .../activity/OnlineFeedViewActivity.java | 12 ++++++++- 2 files changed, 38 insertions(+), 3 deletions(-) (limited to 'src/de/danoeh/antennapod') diff --git a/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java b/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java index 597189885..9c4634d93 100644 --- a/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java +++ b/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java @@ -5,19 +5,26 @@ import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.NavUtils; +import android.util.Log; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.widget.*; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.adapter.FeedItemlistDescriptionAdapter; import de.danoeh.antennapod.asynctask.ImageDiskCache; import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator; import de.danoeh.antennapod.feed.EventDistributor; import de.danoeh.antennapod.feed.Feed; +import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.storage.DBReader; import de.danoeh.antennapod.storage.DownloadRequestException; import de.danoeh.antennapod.storage.DownloadRequester; +import org.apache.commons.lang3.StringUtils; +import org.jsoup.Jsoup; +import org.jsoup.examples.HtmlToPlainText; +import org.jsoup.nodes.Document; import java.util.ArrayList; import java.util.Date; @@ -25,9 +32,11 @@ import java.util.List; import java.util.Map; /** - * Created by daniel on 24.08.13. + * Default implementation of OnlineFeedViewActivity. Shows the downloaded feed's items with their descriptions, + * a subscribe button and a spinner for choosing alternate feed URLs. */ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity { + private static final String TAG = "DefaultOnlineFeedViewActivity"; private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED | EventDistributor.DOWNLOAD_QUEUED | EventDistributor.FEED_LIST_UPDATE; private volatile List feeds; @@ -63,6 +72,22 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity { feeds = DBReader.getFeedList(this); } + @Override + protected void beforeShowFeedInformation(Feed feed, Map alternateFeedUrls) { + super.beforeShowFeedInformation(feed, alternateFeedUrls); + + // remove HTML tags from descriptions + + if (BuildConfig.DEBUG) Log.d(TAG, "Removing HTML from shownotes"); + if (feed.getItems() != null) { + HtmlToPlainText formatter = new HtmlToPlainText(); + for (FeedItem item : feed.getItems()) { + Document description = Jsoup.parse(item.getDescription()); + item.setDescription(StringUtils.trim(formatter.getPlainText(description))); + } + } + } + @Override protected void showFeedInformation(final Feed feed, final Map alternateFeedUrls) { super.showFeedInformation(feed, alternateFeedUrls); @@ -131,7 +156,7 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity { for (String url : alternateFeedUrls.keySet()) { alternateUrlsTitleList.add(alternateFeedUrls.get(url)); } - ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, alternateUrlsTitleList); + ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, alternateUrlsTitleList); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spAlternateUrls.setAdapter(adapter); spAlternateUrls.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { diff --git a/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java index e397ff2ca..322c32741 100644 --- a/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java +++ b/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java @@ -253,6 +253,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity { } if (successful) { + beforeShowFeedInformation(feed, alternateFeedUrls); runOnUiThread(new Runnable() { @Override public void run() { @@ -285,7 +286,16 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity { } /** - * Called when feed parsed successfully + * Called after the feed has been downloaded and parsed and before showFeedInformation is called. + * This method is executed on a background thread + */ + protected void beforeShowFeedInformation(Feed feed, Map alternateFeedUrls) { + + } + + /** + * Called when feed parsed successfully. + * This method is executed on the GUI thread. */ protected void showFeedInformation(Feed feed, Map alternateFeedUrls) { -- cgit v1.2.3 From 859eabb7a302d79948ca9da4ceb886908932482a Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Sun, 15 Jun 2014 21:22:36 +0200 Subject: Added support for itpc-protocol. closes #333 --- src/de/danoeh/antennapod/util/URLChecker.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/de/danoeh/antennapod') diff --git a/src/de/danoeh/antennapod/util/URLChecker.java b/src/de/danoeh/antennapod/util/URLChecker.java index eb522ffa8..af0226ce0 100644 --- a/src/de/danoeh/antennapod/util/URLChecker.java +++ b/src/de/danoeh/antennapod/util/URLChecker.java @@ -33,6 +33,9 @@ public final class URLChecker { } else if (url.startsWith("pcast://")) { if (BuildConfig.DEBUG) Log.d(TAG, "Replacing pcast:// with http://"); url = url.replaceFirst("pcast://", "http://"); + } else if (url.startsWith("itpc")) { + if (BuildConfig.DEBUG) Log.d(TAG, "Replacing itpc:// with http://"); + url = url.replaceFirst("itpc://", "http://"); } else if (!(url.startsWith("http://") || url.startsWith("https://"))) { if (BuildConfig.DEBUG) Log.d(TAG, "Adding http:// at the beginning of the URL"); builder.append("http://"); -- cgit v1.2.3 From 7fc0e73ea7bcf21f843a0d94426e8df515182271 Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Mon, 16 Jun 2014 00:16:48 +0200 Subject: Implemented FeedDiscoverer --- .../util/syndication/FeedDiscoverer.java | 78 ++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/de/danoeh/antennapod/util/syndication/FeedDiscoverer.java (limited to 'src/de/danoeh/antennapod') diff --git a/src/de/danoeh/antennapod/util/syndication/FeedDiscoverer.java b/src/de/danoeh/antennapod/util/syndication/FeedDiscoverer.java new file mode 100644 index 000000000..ac38ec876 --- /dev/null +++ b/src/de/danoeh/antennapod/util/syndication/FeedDiscoverer.java @@ -0,0 +1,78 @@ +package de.danoeh.antennapod.util.syndication; + +import android.net.Uri; +import org.apache.commons.lang3.StringUtils; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import java.io.File; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Finds RSS/Atom URLs in a HTML document using the auto-discovery techniques described here: + *

+ * http://www.rssboard.org/rss-autodiscovery + *

+ * http://blog.whatwg.org/feed-autodiscovery + */ +public class FeedDiscoverer { + + private static final String MIME_RSS = "application/rss+xml"; + private static final String MIME_ATOM = "application/atom+xml"; + + /** + * Discovers links to RSS and Atom feeds in the given File which must be a HTML document. + * + * @return A map which contains the feed URLs as keys and titles as values (the feed URL is also used as a title if + * a title cannot be found). + */ + public Map findLinks(File in, String baseUrl) throws IOException { + return findLinks(Jsoup.parse(in, null), baseUrl); + } + + /** + * Discovers links to RSS and Atom feeds in the given File which must be a HTML document. + * + * @return A map which contains the feed URLs as keys and titles as values (the feed URL is also used as a title if + * a title cannot be found). + */ + public Map findLinks(String in, String baseUrl) throws IOException { + return findLinks(Jsoup.parse(in), baseUrl); + } + + private Map findLinks(Document document, String baseUrl) { + Map res = new LinkedHashMap(); + Elements links = document.head().getElementsByTag("link"); + for (Element link : links) { + String rel = link.attr("rel"); + String href = link.attr("href"); + if (!StringUtils.isEmpty(href) && + (rel.equals("alternate") || rel.equals("feed"))) { + String type = link.attr("type"); + if (type.equals(MIME_RSS) || type.equals(MIME_ATOM)) { + String title = link.attr("title"); + String processedUrl = processURL(baseUrl, href); + if (processedUrl != null) { + res.put(processedUrl, + (StringUtils.isEmpty(title)) ? href : title); + } + } + } + } + return res; + } + + private String processURL(String baseUrl, String strUrl) { + Uri uri = Uri.parse(strUrl); + if (uri.isRelative()) { + Uri res = Uri.parse(baseUrl).buildUpon().path(strUrl).build(); + return (res != null) ? res.toString() : null; + } else { + return strUrl; + } + } +} -- cgit v1.2.3 From 30017a316e1a514e2441f45ab1545442fe94c0b3 Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Mon, 16 Jun 2014 01:22:46 +0200 Subject: Implemented Feed-discovery in OnlineFeedView --- .../activity/OnlineFeedViewActivity.java | 81 +++++++++++++++++++++- .../antennapod/syndication/handler/TypeGetter.java | 18 ++++- .../handler/UnsupportedFeedtypeException.java | 19 +++-- 3 files changed, 108 insertions(+), 10 deletions(-) (limited to 'src/de/danoeh/antennapod') diff --git a/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java index 322c32741..2c6d75cd8 100644 --- a/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java +++ b/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java @@ -9,6 +9,7 @@ import android.content.Intent; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.util.Log; +import android.widget.ArrayAdapter; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.RelativeLayout; @@ -29,13 +30,16 @@ import de.danoeh.antennapod.util.DownloadError; import de.danoeh.antennapod.util.FileNameGenerator; import de.danoeh.antennapod.util.StorageUtils; import de.danoeh.antennapod.util.URLChecker; +import de.danoeh.antennapod.util.syndication.FeedDiscoverer; import org.apache.commons.lang3.StringUtils; import org.xml.sax.SAXException; import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.Map; /** @@ -127,6 +131,13 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity { } } + private void resetIntent(String url, String title) { + Intent intent = new Intent(); + intent.putExtra(ARG_FEEDURL, url); + intent.putExtra(ARG_TITLE, title); + setIntent(intent); + } + private void onDownloadCompleted(final Downloader downloader) { runOnUiThread(new Runnable() { @@ -244,8 +255,15 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity { e.printStackTrace(); reasonDetailed = e.getMessage(); } catch (UnsupportedFeedtypeException e) { - e.printStackTrace(); - reasonDetailed = e.getMessage(); + if (BuildConfig.DEBUG) Log.d(TAG, "Unsupported feed type detected"); + if (StringUtils.equalsIgnoreCase("html", e.getRootElement())) { + if (showFeedDiscoveryDialog(new File(feed.getFile_url()), feed.getDownload_url())) { + return; + } + } else { + e.printStackTrace(); + reasonDetailed = e.getMessage(); + } } finally { boolean rc = new File(feed.getFile_url()).delete(); if (BuildConfig.DEBUG) @@ -326,9 +344,67 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity { finish(); } }); + builder.show(); } } + private boolean showFeedDiscoveryDialog(File feedFile, String baseUrl) { + FeedDiscoverer fd = new FeedDiscoverer(); + final Map urlsMap; + try { + urlsMap = fd.findLinks(feedFile, baseUrl); + if (urlsMap == null || urlsMap.isEmpty()) { + return false; + } + } catch (IOException e) { + e.printStackTrace(); + return false; + } + + runOnUiThread(new Runnable() { + @Override + public void run() { + if (isPaused || isFinishing()) { + return; + } + + final List titles = new ArrayList(); + final List urls = new ArrayList(); + + urls.addAll(urlsMap.keySet()); + for (String url : urls) { + titles.add(urlsMap.get(url)); + } + + final ArrayAdapter adapter = new ArrayAdapter(OnlineFeedViewActivity.this, R.layout.ellipsize_start_listitem, R.id.txtvTitle, titles); + DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + String selectedUrl = urls.get(which); + dialog.dismiss(); + resetIntent(selectedUrl, titles.get(which)); + startFeedDownload(selectedUrl, null, null); + } + }; + + AlertDialog.Builder ab = new AlertDialog.Builder(OnlineFeedViewActivity.this) + .setTitle(R.string.feeds_label) + .setCancelable(true) + .setOnCancelListener(new OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + finish(); + } + }) + .setAdapter(adapter, onClickListener); + ab.show(); + } + }); + + + return true; + } + private class FeedViewAuthenticationDialog extends AuthenticationDialog { private String feedUrl; @@ -349,5 +425,4 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity { startFeedDownload(feedUrl, username, password); } } - } diff --git a/src/de/danoeh/antennapod/syndication/handler/TypeGetter.java b/src/de/danoeh/antennapod/syndication/handler/TypeGetter.java index 5ed9ff2b0..2496e112a 100644 --- a/src/de/danoeh/antennapod/syndication/handler/TypeGetter.java +++ b/src/de/danoeh/antennapod/syndication/handler/TypeGetter.java @@ -4,6 +4,8 @@ import android.util.Log; import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.feed.Feed; import org.apache.commons.io.input.XmlStreamReader; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; @@ -64,7 +66,7 @@ public class TypeGetter { } else { if (BuildConfig.DEBUG) Log.d(TAG, "Type is invalid"); - throw new UnsupportedFeedtypeException(Type.INVALID); + throw new UnsupportedFeedtypeException(Type.INVALID, tag); } } else { eventType = xpp.next(); @@ -73,7 +75,19 @@ public class TypeGetter { } catch (XmlPullParserException e) { e.printStackTrace(); - } catch (IOException e) { + // XML document might actually be a HTML document -> try to parse as HTML + String rootElement = null; + try { + if (Jsoup.parse(new File(feed.getFile_url()), null) != null) { + rootElement = "html"; + } + } catch (IOException e1) { + e1.printStackTrace(); + } finally { + throw new UnsupportedFeedtypeException(Type.INVALID, rootElement); + } + + } catch (IOException e) { e.printStackTrace(); } } diff --git a/src/de/danoeh/antennapod/syndication/handler/UnsupportedFeedtypeException.java b/src/de/danoeh/antennapod/syndication/handler/UnsupportedFeedtypeException.java index 67fbc9cc9..605dad2fb 100644 --- a/src/de/danoeh/antennapod/syndication/handler/UnsupportedFeedtypeException.java +++ b/src/de/danoeh/antennapod/syndication/handler/UnsupportedFeedtypeException.java @@ -5,18 +5,27 @@ import de.danoeh.antennapod.syndication.handler.TypeGetter.Type; public class UnsupportedFeedtypeException extends Exception { private static final long serialVersionUID = 9105878964928170669L; private TypeGetter.Type type; + private String rootElement; public UnsupportedFeedtypeException(Type type) { super(); this.type = type; - } - - public TypeGetter.Type getType() { + + public UnsupportedFeedtypeException(Type type, String rootElement) { + this.type = type; + this.rootElement = rootElement; + } + + public TypeGetter.Type getType() { return type; } - - @Override + + public String getRootElement() { + return rootElement; + } + + @Override public String getMessage() { if (type == TypeGetter.Type.INVALID) { return "Invalid type"; -- cgit v1.2.3 From ff612a04cdf8097a4d7a3be69032d71e4a8495da Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Mon, 16 Jun 2014 01:26:48 +0200 Subject: Fixed: NullPointerException in OnlineFeedView --- .../danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/de/danoeh/antennapod') diff --git a/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java b/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java index 9c4634d93..c129d89ed 100644 --- a/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java +++ b/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java @@ -82,8 +82,10 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity { if (feed.getItems() != null) { HtmlToPlainText formatter = new HtmlToPlainText(); for (FeedItem item : feed.getItems()) { - Document description = Jsoup.parse(item.getDescription()); - item.setDescription(StringUtils.trim(formatter.getPlainText(description))); + if (item.getDescription() != null) { + Document description = Jsoup.parse(item.getDescription()); + item.setDescription(StringUtils.trim(formatter.getPlainText(description))); + } } } } -- cgit v1.2.3 From c9c69aa7c796da59c29fad2c4d4c9464d353416b Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Sun, 29 Jun 2014 02:38:25 +0200 Subject: Added first implementation of the Timeline class --- src/de/danoeh/antennapod/util/Converter.java | 21 +++ .../danoeh/antennapod/util/playback/Timeline.java | 152 +++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 src/de/danoeh/antennapod/util/playback/Timeline.java (limited to 'src/de/danoeh/antennapod') diff --git a/src/de/danoeh/antennapod/util/Converter.java b/src/de/danoeh/antennapod/util/Converter.java index 46a0d30b4..bc3d9edd3 100644 --- a/src/de/danoeh/antennapod/util/Converter.java +++ b/src/de/danoeh/antennapod/util/Converter.java @@ -78,5 +78,26 @@ public final class Converter { return String.format("%02d:%02d", h, m); } + + /** Converts long duration string (HH:MM:SS) to milliseconds. */ + public static long durationStringLongToMs(String input) { + String[] parts = input.split(":"); + if (parts.length != 3) { + return 0; + } + return Long.valueOf(parts[0]) * 3600 * 1000 + + Long.valueOf(parts[1]) * 60 * 1000 + + Long.valueOf(parts[2]) * 1000; + } + + /** Converts short duration string (HH:MM) to milliseconds. */ + public static long durationStringShortToMs(String input) { + String[] parts = input.split(":"); + if (parts.length != 2) { + return 0; + } + return Long.valueOf(parts[0]) * 3600 * 1000 + + Long.valueOf(parts[1]) * 1000 * 60; + } } diff --git a/src/de/danoeh/antennapod/util/playback/Timeline.java b/src/de/danoeh/antennapod/util/playback/Timeline.java new file mode 100644 index 000000000..6e00f725c --- /dev/null +++ b/src/de/danoeh/antennapod/util/playback/Timeline.java @@ -0,0 +1,152 @@ +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.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. + *

+ * 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 = "%s"; - final int pageMargin = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, 8, getResources() - .getDisplayMetrics()); - return String.format(WEBVIEW_STYLE, textColor, "100%", pageMargin, - pageMargin, pageMargin, pageMargin, data); - } - private View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() { @Override @@ -254,10 +269,13 @@ public class ItemDescriptionFragment extends Fragment { if (BuildConfig.DEBUG) Log.d(TAG, "Link of webview was long-pressed. Extra: " - + r.getExtra()); + + r.getExtra() + ); selectedURL = r.getExtra(); - webvDescription.showContextMenu(); - return true; + if (!Timeline.isTimecodeLink(selectedURL)) { + webvDescription.showContextMenu(); + return true; + } } selectedURL = null; return false; @@ -364,22 +382,10 @@ public class ItemDescriptionFragment extends Fragment { if (BuildConfig.DEBUG) Log.d(TAG, "Loading Webview"); try { - Callable shownotesLoadTask = shownotesProvider.loadShownotes(); - final String shownotes = shownotesLoadTask.call(); - - data = StringEscapeUtils.unescapeHtml4(shownotes); Activity activity = getActivity(); if (activity != null) { - TypedArray res = activity - .getTheme() - .obtainStyledAttributes( - new int[]{android.R.attr.textColorPrimary}); - int colorResource = res.getColor(0, 0); - String colorString = String.format("#%06X", - 0xFFFFFF & colorResource); - Log.i(TAG, "text color: " + colorString); - res.recycle(); - data = applyWebviewStyle(colorString, data); + Timeline timeline = new Timeline(activity, shownotesProvider); + data = timeline.processShownotes(highlightTimecodes); } else { cancel(true); } @@ -409,7 +415,8 @@ public class ItemDescriptionFragment extends Fragment { if (BuildConfig.DEBUG) Log.d(TAG, "Saving scroll position: " - + webvDescription.getScrollY()); + + webvDescription.getScrollY() + ); editor.putInt(PREF_SCROLL_Y, webvDescription.getScrollY()); editor.putString(PREF_PLAYABLE_ID, media.getIdentifier() .toString()); @@ -447,4 +454,8 @@ public class ItemDescriptionFragment extends Fragment { } return false; } + + public interface ItemDescriptionFragmentCallback { + public PlaybackController getPlaybackController(); + } } diff --git a/src/de/danoeh/antennapod/util/Converter.java b/src/de/danoeh/antennapod/util/Converter.java index bc3d9edd3..f4c2b2f66 100644 --- a/src/de/danoeh/antennapod/util/Converter.java +++ b/src/de/danoeh/antennapod/util/Converter.java @@ -80,24 +80,24 @@ public final class Converter { } /** Converts long duration string (HH:MM:SS) to milliseconds. */ - public static long durationStringLongToMs(String input) { + public static int durationStringLongToMs(String input) { String[] parts = input.split(":"); if (parts.length != 3) { return 0; } - return Long.valueOf(parts[0]) * 3600 * 1000 + - Long.valueOf(parts[1]) * 60 * 1000 + - Long.valueOf(parts[2]) * 1000; + return Integer.valueOf(parts[0]) * 3600 * 1000 + + Integer.valueOf(parts[1]) * 60 * 1000 + + Integer.valueOf(parts[2]) * 1000; } /** Converts short duration string (HH:MM) to milliseconds. */ - public static long durationStringShortToMs(String input) { + public static int durationStringShortToMs(String input) { String[] parts = input.split(":"); if (parts.length != 2) { return 0; } - return Long.valueOf(parts[0]) * 3600 * 1000 + - Long.valueOf(parts[1]) * 1000 * 60; + return Integer.valueOf(parts[0]) * 3600 * 1000 + + Integer.valueOf(parts[1]) * 1000 * 60; } } diff --git a/src/de/danoeh/antennapod/util/playback/PlaybackController.java b/src/de/danoeh/antennapod/util/playback/PlaybackController.java index 5783b5bc5..a979ddc1c 100644 --- a/src/de/danoeh/antennapod/util/playback/PlaybackController.java +++ b/src/de/danoeh/antennapod/util/playback/PlaybackController.java @@ -680,6 +680,12 @@ public abstract class PlaybackController { } } + public void seekTo(int time) { + if (playbackService != null) { + playbackService.seekTo(time); + } + } + public void setVideoSurface(SurfaceHolder holder) { if (playbackService != null) { playbackService.setVideoSurface(holder); diff --git a/src/de/danoeh/antennapod/util/playback/Timeline.java b/src/de/danoeh/antennapod/util/playback/Timeline.java index 6e00f725c..33ffb054c 100644 --- a/src/de/danoeh/antennapod/util/playback/Timeline.java +++ b/src/de/danoeh/antennapod/util/playback/Timeline.java @@ -27,7 +27,7 @@ import de.danoeh.antennapod.util.ShownotesProvider; public class Timeline { private static final String TAG = "Timeline"; - private static final String WEBVIEW_STYLE = "