Merge branch 'playback-speed' into speed

Conflicts:
	res/values/arrays.xml
	res/values/strings.xml
	src/de/danoeh/antennapod/activity/PreferenceActivity.java
	src/de/danoeh/antennapod/service/PlaybackService.java
This commit is contained in:
James Falcon 2013-05-06 21:48:18 -05:00
commit b48c3807fd
17 changed files with 220 additions and 40 deletions

View File

@ -23,6 +23,9 @@
<uses-feature
android:name="android.hardware.screen.portrait"
android:required="false" />
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
@ -368,4 +371,4 @@
</receiver>
</application>
</manifest>
</manifest>

View File

@ -70,6 +70,14 @@
<version>0.6.1-SNAPSHOT</version>
<type>apklib</type>
</dependency>
<dependency>
<groupId>com.aocate</groupId>
<artifactId>presto_client</artifactId>
<version>0.8.5</version>
<type>jar</type>
<scope>system</scope>
<systemPath>${project.basedir}/libs/presto_client-0.8.5.jar</systemPath>
</dependency>
</dependencies>
<build>

View File

@ -92,14 +92,12 @@
android:layout_width="80dp"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="?attr/borderless_button"
android:src="?attr/av_pause" />
<ImageButton
android:id="@+id/butRev"
android:layout_width="80dp"
android:layout_width="60dp"
android:layout_height="match_parent"
android:layout_toLeftOf="@id/butPlay"
android:background="?attr/borderless_button"
@ -107,11 +105,22 @@
<ImageButton
android:id="@+id/butFF"
android:layout_width="80dp"
android:layout_width="60dp"
android:layout_height="match_parent"
android:layout_toRightOf="@id/butPlay"
android:background="?attr/borderless_button"
android:src="?attr/av_fast_forward" />
<Button
android:id="@+id/butPlaybackSpeed"
android:layout_width="60dp"
android:layout_height="match_parent"
android:layout_toRightOf="@id/butFF"
android:background="?attr/borderless_button"
android:src="?attr/av_fast_forward"
android:textColor="@color/gray"
android:textSize="@dimen/text_size_medium"
android:visibility="gone" />
</RelativeLayout>
<RelativeLayout

View File

@ -79,8 +79,6 @@
android:layout_width="80dp"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:background="?attr/borderless_button"
android:src="?attr/av_pause" />
@ -99,6 +97,17 @@
android:layout_toRightOf="@id/butPlay"
android:background="?attr/borderless_button"
android:src="?attr/av_fast_forward" />
<Button
android:id="@+id/butPlaybackSpeed"
android:layout_width="80dp"
android:layout_height="match_parent"
android:layout_toRightOf="@id/butFF"
android:background="?attr/borderless_button"
android:src="?attr/av_fast_forward"
android:textColor="@color/gray"
android:textSize="@dimen/text_size_medium"
android:visibility="gone" />
</RelativeLayout>
<RelativeLayout

View File

@ -20,7 +20,6 @@
<item>12</item>
<item>24</item>
</string-array>
<string-array name="episode_cache_size_entries">
<item>@string/pref_episode_cache_unlimited</item>
<item>10</item>
@ -30,7 +29,6 @@
<item>80</item>
<item>100</item>
</string-array>
<string-array name="episode_cache_size_values">
<item>-1</item>
<item>10</item>
@ -40,7 +38,6 @@
<item>80</item>
<item>100</item>
</string-array>
<string-array name="playback_speed_values">
<item>1.0</item>
<item>1.10</item>
@ -58,16 +55,13 @@
<string-array name="autodl_select_networks_default_entries">
<item>N/A</item>
</string-array>
<string-array name="autodl_select_networks_default_values">
<item>0</item>
</string-array>
<string-array name="theme_options">
<item>@string/pref_theme_title_light</item>
<item>@string/pref_theme_title_dark</item>
</string-array>
<string-array name="theme_values">
<item>0</item>
<item>1</item>

View File

@ -190,8 +190,12 @@
<string name="pref_theme_title_light">Light</string>
<string name="pref_theme_title_dark">Dark</string>
<string name="pref_episode_cache_unlimited">Unlimited</string>
<string name="pref_update_interval_hours_plural">hours</string>
<string name="pref_update_interval_hours_singular">hour</string>
<string name="pref_update_interval_hours_manual">Manual</string>
<string name="pref_playback_speed_title">Playback Speed</string>
<string name="pref_playback_speed_sum">Change the speed of audio playback using a 3rd party control</string>
<!-- Search -->
<string name="search_hint">Search for Feeds or Episodes</string>

View File

@ -26,7 +26,7 @@
<PreferenceCategory android:title="@string/network_pref" >
<ListPreference
android:defaultValue="0"
android:entries="@array/update_intervall_options"
android:entries="@array/update_intervall_values"
android:entryValues="@array/update_intervall_values"
android:key="prefAutoUpdateIntervall"
android:summary="@string/pref_autoUpdateIntervall_sum"

View File

@ -11,6 +11,7 @@ import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView.ScaleType;
import android.widget.ListView;
@ -57,6 +58,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
private TextView txtvTitle;
private TextView txtvFeed;
private Button butPlaybackSpeed;
private ImageButton butNavLeft;
private ImageButton butNavRight;
@ -219,7 +221,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
if (savedPosition != -1) {
switchToFragment(savedPosition);
}
}
@Override
@ -365,6 +367,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
txtvFeed = (TextView) findViewById(R.id.txtvFeed);
butNavLeft = (ImageButton) findViewById(R.id.butNavLeft);
butNavRight = (ImageButton) findViewById(R.id.butNavRight);
butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed);
butNavLeft.setOnClickListener(new OnClickListener() {
@ -392,6 +395,50 @@ public class AudioplayerActivity extends MediaplayerActivity {
}
}
});
butPlaybackSpeed.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
final double PLAYBACK_SPEED_STEP = 0.5;
final double PLAYBACK_SPEED_MAX = 2.0;
final double PLAYBACK_SPEED_DEFAULT = 1.0;
if (controller != null && controller.canSetPlaybackSpeed()) {
double currentPlaybackSpeed = controller
.getCurrentPlaybackSpeedMultiplier();
if (currentPlaybackSpeed != -1) {
if (currentPlaybackSpeed >= PLAYBACK_SPEED_MAX) {
controller.setPlaybackSpeed(PLAYBACK_SPEED_DEFAULT);
} else {
controller.setPlaybackSpeed(currentPlaybackSpeed
+ PLAYBACK_SPEED_STEP);
}
} else {
controller.setPlaybackSpeed(PLAYBACK_SPEED_DEFAULT);
}
}
}
});
}
@Override
protected void onPlaybackSpeedChange() {
super.onPlaybackSpeedChange();
updateButPlaybackSpeed();
}
private void updateButPlaybackSpeed() {
double playbackSpeed;
if (controller == null
|| (playbackSpeed = controller
.getCurrentPlaybackSpeedMultiplier()) == -1) {
butPlaybackSpeed.setVisibility(View.GONE);
} else {
butPlaybackSpeed.setVisibility(View.VISIBLE);
butPlaybackSpeed.setText(String.format("%.1fx", playbackSpeed));
}
}
@Override
@ -423,7 +470,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
((AudioplayerContentFragment) currentlyShownFragment)
.onDataSetChanged(media);
}
updateButPlaybackSpeed();
}
public void notifyMediaPositionChanged() {

View File

@ -132,10 +132,19 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
public void onPlaybackEnd() {
finish();
}
@Override
public void onPlaybackSpeedChange() {
MediaplayerActivity.this.onPlaybackSpeedChange();
}
};
}
protected void onPlaybackSpeedChange() {
}
protected void onServiceQueried() {
supportInvalidateOptionsMenu();
}

View File

@ -14,6 +14,7 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
@ -178,13 +179,40 @@ public class PreferenceActivity extends SherlockPreferenceActivity {
return true;
}
});
buildUpdateIntervalPreference();
buildAutodownloadSelectedNetworsPreference();
setSelectedNetworksEnabled(UserPreferences
.isEnableAutodownloadWifiFilter());
}
private void buildUpdateIntervalPreference() {
ListPreference pref = (ListPreference) findPreference(UserPreferences.PREF_UPDATE_INTERVAL);
String[] values = getResources().getStringArray(
R.array.update_intervall_values);
String[] entries = new String[values.length];
for (int x = 0; x < values.length; x++) {
Integer v = Integer.parseInt(values[x]);
switch (v) {
case 0:
entries[x] = getString(R.string.pref_update_interval_hours_manual);
break;
case 1:
entries[x] = v
+ " "
+ getString(R.string.pref_update_interval_hours_singular);
break;
default:
entries[x] = v + " "
+ getString(R.string.pref_update_interval_hours_plural);
break;
}
}
pref.setEntries(entries);
}
private void setSelectedNetworksEnabled(boolean b) {
if (selectedNetworks != null) {
for (Preference p : selectedNetworks) {

View File

@ -677,8 +677,12 @@ public class FeedManager {
int deletedEpisodes = performAutoCleanup(context,
getPerformAutoCleanupArgs(undownloadedEpisodes));
int episodeSpaceLeft = undownloadedEpisodes;
if (UserPreferences.getEpisodeCacheSize() < downloadedEpisodes
+ undownloadedEpisodes) {
boolean cacheIsUnlimited = UserPreferences.getEpisodeCacheSize() == UserPreferences
.getEpisodeCacheSizeUnlimited();
if (!cacheIsUnlimited
&& UserPreferences.getEpisodeCacheSize() < downloadedEpisodes
+ undownloadedEpisodes) {
episodeSpaceLeft = UserPreferences.getEpisodeCacheSize()
- (downloadedEpisodes - deletedEpisodes);
}
@ -733,7 +737,9 @@ public class FeedManager {
* that the number of episodes fits into the episode cache.
* */
private int getPerformAutoCleanupArgs(final int episodeNumber) {
if (episodeNumber >= 0 && UserPreferences.getEpisodeCacheSize() != UserPreferences.getEpisodeCacheSizeUnlimited()) {
if (episodeNumber >= 0
&& UserPreferences.getEpisodeCacheSize() != UserPreferences
.getEpisodeCacheSizeUnlimited()) {
int downloadedEpisodes = getNumberOfDownloadedEpisodes();
if (downloadedEpisodes + episodeNumber >= UserPreferences
.getEpisodeCacheSize()) {
@ -765,7 +771,8 @@ public class FeedManager {
List<FeedItem> delete;
for (Feed feed : feeds) {
for (FeedItem item : feed.getItems()) {
if (item.hasMedia() && item.getMedia().isDownloaded() && !isInQueue(item) && item.isRead()) {
if (item.hasMedia() && item.getMedia().isDownloaded()
&& !isInQueue(item) && item.isRead()) {
candidates.add(item);
}
}

View File

@ -174,6 +174,12 @@ public class ExternalPlayerFragment extends SherlockFragment {
.newOnPlayButtonClickListener());
}
}
@Override
public void onPlaybackSpeedChange() {
// TODO Auto-generated method stub
}
};
}

View File

@ -446,17 +446,21 @@ public class ItemDescriptionFragment extends SherlockFragment {
if (saveState) {
if (AppConfig.DEBUG)
Log.d(TAG, "Restoring from preferences");
SharedPreferences prefs = getActivity().getSharedPreferences(PREF,
Activity.MODE_PRIVATE);
String id = prefs.getString(PREF_PLAYABLE_ID, "");
int scrollY = prefs.getInt(PREF_SCROLL_Y, -1);
if (scrollY != -1 && media != null
&& id.equals(media.getIdentifier().toString())
&& webvDescription != null) {
if (AppConfig.DEBUG)
Log.d(TAG, "Restored scroll Position: " + scrollY);
webvDescription.scrollTo(webvDescription.getScrollX(), scrollY);
return true;
Activity activity = getActivity();
if (activity != null) {
SharedPreferences prefs = activity.getSharedPreferences(
PREF, Activity.MODE_PRIVATE);
String id = prefs.getString(PREF_PLAYABLE_ID, "");
int scrollY = prefs.getInt(PREF_SCROLL_Y, -1);
if (scrollY != -1 && media != null
&& id.equals(media.getIdentifier().toString())
&& webvDescription != null) {
if (AppConfig.DEBUG)
Log.d(TAG, "Restored scroll Position: " + scrollY);
webvDescription.scrollTo(webvDescription.getScrollX(),
scrollY);
return true;
}
}
}
return false;

View File

@ -110,6 +110,7 @@ public class PlaybackService extends Service {
public static final int NOTIFICATION_TYPE_BUFFER_END = 6;
/** No more episodes are going to be played. */
public static final int NOTIFICATION_TYPE_PLAYBACK_END = 7;
public static final int NOTIFICATION_TYPE_PLAYBACK_SPEED_CHANGE = 8;
/**
* Returned by getPositionSafe() or getDurationSafe() if the playbackService
@ -395,12 +396,14 @@ public class PlaybackService extends Service {
}
// Intent values appear to be valid
// check if already playing and playbackType is the same
} else if (media == null || playable != media
} else if (media == null
|| !playable.getIdentifier().equals(media.getIdentifier())
|| playbackType != shouldStream) {
pause(true, false);
sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, 0);
if (media == null
|| playable.getIdentifier() != media.getIdentifier()) {
|| !playable.getIdentifier().equals(
media.getIdentifier())) {
media = playable;
}
@ -1531,30 +1534,34 @@ public class PlaybackService extends Service {
}
public boolean canSetSpeed() {
if (media.getMediaType() == MediaType.AUDIO) {
if (media != null && media.getMediaType() == MediaType.AUDIO) {
return ((AudioPlayer) player).canSetSpeed();
}
return false;
}
public boolean canSetPitch() {
if (media.getMediaType() == MediaType.AUDIO) {
if (media != null && media.getMediaType() == MediaType.AUDIO) {
return ((AudioPlayer) player).canSetPitch();
}
return false;
}
public void setSpeed(float speed) {
if (media.getMediaType() == MediaType.AUDIO) {
if (media != null && media.getMediaType() == MediaType.AUDIO) {
AudioPlayer audioPlayer = (AudioPlayer) player;
if (audioPlayer.canSetSpeed()) {
audioPlayer.setPlaybackSpeed(speed);
if (AppConfig.DEBUG)
Log.d(TAG, "Playback speed was set to " + speed);
sendNotificationBroadcast(
NOTIFICATION_TYPE_PLAYBACK_SPEED_CHANGE, 0);
}
}
}
public void setPitch(float pitch) {
if (media.getMediaType() == MediaType.AUDIO) {
if (media != null && media.getMediaType() == MediaType.AUDIO) {
AudioPlayer audioPlayer = (AudioPlayer) player;
if (audioPlayer.canSetPitch()) {
audioPlayer.setPlaybackPitch(pitch);
@ -1562,6 +1569,17 @@ public class PlaybackService extends Service {
}
}
public double getCurrentPlaybackSpeed() {
if (media.getMediaType() == MediaType.AUDIO
&& player instanceof AudioPlayer) {
AudioPlayer audioPlayer = (AudioPlayer) player;
if (audioPlayer.canSetSpeed()) {
return audioPlayer.getCurrentSpeedMultiplier();
}
}
return -1;
}
/**
* call getDuration() on mediaplayer or return INVALID_TIME if player is in
* an invalid state. This method should be used instead of calling

View File

@ -78,6 +78,15 @@ public class NSRSS20 extends Namespace {
@Override
public void handleElementEnd(String localName, HandlerState state) {
if (localName.equals(ITEM)) {
if (state.getCurrentItem() != null) {
// the title tag is optional in RSS 2.0. The description is used
// as a
// title if the item has no title-tag.
if (state.getCurrentItem().getTitle() == null) {
state.getCurrentItem().setTitle(
state.getCurrentItem().getDescription());
}
}
state.setCurrentItem(null);
} else if (state.getTagstack().size() >= 2
&& state.getContentBuf() != null) {
@ -98,7 +107,8 @@ public class NSRSS20 extends Namespace {
state.getCurrentItem().setTitle(content);
} else if (second.equals(CHANNEL)) {
state.getFeed().setTitle(content);
} else if (second.equals(IMAGE) && third != null && third.equals(CHANNEL)) {
} else if (second.equals(IMAGE) && third != null
&& third.equals(CHANNEL)) {
state.getFeed().getImage().setTitle(content);
}
} else if (top.equals(LINK)) {
@ -110,7 +120,8 @@ public class NSRSS20 extends Namespace {
} else if (top.equals(PUBDATE) && second.equals(ITEM)) {
state.getCurrentItem().setPubDate(
SyndDateUtils.parseRFC822Date(content));
} else if (top.equals(URL) && second.equals(IMAGE) && third != null && third.equals(CHANNEL)) {
} else if (top.equals(URL) && second.equals(IMAGE) && third != null
&& third.equals(CHANNEL)) {
state.getFeed().getImage().setDownload_url(content);
} else if (localName.equals(DESCR)) {
if (second.equals(CHANNEL)) {

View File

@ -327,6 +327,8 @@ public abstract class PlaybackController {
break;
case PlaybackService.NOTIFICATION_TYPE_PLAYBACK_END:
onPlaybackEnd();
case PlaybackService.NOTIFICATION_TYPE_PLAYBACK_SPEED_CHANGE:
onPlaybackSpeedChange();
break;
}
@ -354,6 +356,8 @@ public abstract class PlaybackController {
}
}
};
public abstract void onPlaybackSpeedChange();
public abstract void onShutdownNotification();
@ -654,6 +658,24 @@ public abstract class PlaybackController {
return false;
}
public boolean canSetPlaybackSpeed() {
return playbackService != null && playbackService.canSetSpeed();
}
public void setPlaybackSpeed(double speed) {
if (playbackService != null) {
playbackService.setSpeed(speed);
}
}
public double getCurrentPlaybackSpeedMultiplier() {
if (canSetPlaybackSpeed()) {
return playbackService.getCurrentPlaybackSpeed();
} else {
return -1;
}
}
/**
* Returns true if PlaybackController can communicate with the playback
* service.

View File

@ -3,6 +3,7 @@ package de.danoeh.antennapod.test;
public class TestFeeds {
public static final String[] urls = {
"http://savoirsenmultimedia.ens.fr/podcast.php?id=30",
"http://bitlove.org/apollo40/ps3newsroom/feed",
"http://bitlove.org/beapirate/hauptstadtpiraten/feed",
"http://bitlove.org/benni/besondereumstaende/feed",