Merge branch 'playback-speed' into develop
Conflicts: proguard.cfg src/de/danoeh/antennapod/storage/DBTasks.java
This commit is contained in:
commit
b1911e5ff7
12
build.gradle
12
build.gradle
|
@ -12,6 +12,17 @@ repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
|
def libsdir = new File('libs');
|
||||||
|
if (!libsdir.exists()) {
|
||||||
|
println "Creating libs directory"
|
||||||
|
libsdir.mkdir()
|
||||||
|
}
|
||||||
|
def prestoLib = new File('libs/presto_client-0.8.5.jar')
|
||||||
|
if (!prestoLib.exists()) {
|
||||||
|
println "Downloading presto library into libs folder"
|
||||||
|
new URL('http://www.aocate.com/presto/client/presto_client-0.8.5.jar').withInputStream{ i -> prestoLib.withOutputStream{ it << i }}
|
||||||
|
}
|
||||||
|
|
||||||
compile 'com.android.support:appcompat-v7:18.0.+'
|
compile 'com.android.support:appcompat-v7:18.0.+'
|
||||||
compile 'org.apache.commons:commons-lang3:3.1'
|
compile 'org.apache.commons:commons-lang3:3.1'
|
||||||
compile ('org.shredzone.flattr4j:flattr4j-core:2.4') {
|
compile ('org.shredzone.flattr4j:flattr4j-core:2.4') {
|
||||||
|
@ -22,6 +33,7 @@ dependencies {
|
||||||
compile 'commons-io:commons-io:2.4'
|
compile 'commons-io:commons-io:2.4'
|
||||||
compile 'com.nineoldandroids:library:2.4.0'
|
compile 'com.nineoldandroids:library:2.4.0'
|
||||||
compile project(':submodules:dslv:library')
|
compile project(':submodules:dslv:library')
|
||||||
|
compile files('libs/presto_client-0.8.5.jar')
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
|
10
pom.xml
10
pom.xml
|
@ -84,6 +84,14 @@
|
||||||
<artifactId>library</artifactId>
|
<artifactId>library</artifactId>
|
||||||
<version>2.4.0</version>
|
<version>2.4.0</version>
|
||||||
</dependency>
|
</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>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -212,7 +220,7 @@
|
||||||
</manifest>
|
</manifest>
|
||||||
<proguard>
|
<proguard>
|
||||||
<skip>false</skip>
|
<skip>false</skip>
|
||||||
<config>proguard.cfg</config>
|
<config>proguard-mvn.cfg</config>
|
||||||
</proguard>
|
</proguard>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
-printmapping out.map
|
||||||
|
-renamesourcefileattribute SourceFile
|
||||||
|
-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
-dontpreverify
|
||||||
|
-repackageclasses ''
|
||||||
|
-allowaccessmodification
|
||||||
|
-optimizations !code/simplification/arithmetic
|
||||||
|
-keepattributes *Annotation*
|
||||||
|
|
||||||
|
-injars libs/presto_client-0.8.5.jar
|
||||||
|
|
||||||
|
-keep public class * extends android.app.Activity
|
||||||
|
-keep public class * extends android.app.Application
|
||||||
|
-keep public class * extends android.app.Service
|
||||||
|
-keep public class * extends android.content.BroadcastReceiver
|
||||||
|
-keep public class * extends android.content.ContentProvider
|
||||||
|
|
||||||
|
-keep public class * extends android.view.View {
|
||||||
|
public <init>(android.content.Context);
|
||||||
|
public <init>(android.content.Context, android.util.AttributeSet);
|
||||||
|
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||||
|
public void set*(...);
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclassmembers enum * {
|
||||||
|
public static **[] values();
|
||||||
|
public static ** valueOf(java.lang.String);
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclasseswithmembers class * {
|
||||||
|
public <init>(android.content.Context, android.util.AttributeSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclasseswithmembers class * {
|
||||||
|
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclassmembers class * extends android.content.Context {
|
||||||
|
public void *(android.view.View);
|
||||||
|
public void *(android.view.MenuItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclassmembers class * implements android.os.Parcelable {
|
||||||
|
static android.os.Parcelable$Creator CREATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclassmembers class **.R$* {
|
||||||
|
public static <fields>;
|
||||||
|
}
|
||||||
|
|
||||||
|
-keep class android.support.v4.** { *; }
|
||||||
|
-keep interface android.support.v4.** { *; }
|
||||||
|
-keep class android.support.v7.** { *; }
|
||||||
|
-keep interface android.support.v7.** { *; }
|
||||||
|
-dontwarn android.support.v4.**
|
||||||
|
-dontwarn android.support.v7.**
|
||||||
|
|
||||||
|
-keepattributes *Annotation*
|
||||||
|
|
||||||
|
-keep class org.shredzone.flattr4j.** { *; }
|
||||||
|
-dontwarn org.shredzone.flattr4j.**
|
||||||
|
|
||||||
|
-keep class org.apache.commons.** { *; }
|
||||||
|
|
||||||
|
-dontskipnonpubliclibraryclassmembers
|
|
@ -8,6 +8,8 @@
|
||||||
-optimizations !code/simplification/arithmetic
|
-optimizations !code/simplification/arithmetic
|
||||||
-keepattributes *Annotation*
|
-keepattributes *Annotation*
|
||||||
|
|
||||||
|
#-injars libs/presto_client-0.8.5.jar
|
||||||
|
|
||||||
-keep public class * extends android.app.Activity
|
-keep public class * extends android.app.Activity
|
||||||
-keep public class * extends android.app.Application
|
-keep public class * extends android.app.Application
|
||||||
-keep public class * extends android.app.Service
|
-keep public class * extends android.app.Service
|
||||||
|
|
|
@ -92,14 +92,12 @@
|
||||||
android:layout_width="80dp"
|
android:layout_width="80dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_centerHorizontal="true"
|
android:layout_centerHorizontal="true"
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
android:layout_marginRight="8dp"
|
|
||||||
android:background="?attr/borderless_button"
|
android:background="?attr/borderless_button"
|
||||||
android:src="?attr/av_pause" />
|
android:src="?attr/av_pause" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/butRev"
|
android:id="@+id/butRev"
|
||||||
android:layout_width="80dp"
|
android:layout_width="60dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_toLeftOf="@id/butPlay"
|
android:layout_toLeftOf="@id/butPlay"
|
||||||
android:background="?attr/borderless_button"
|
android:background="?attr/borderless_button"
|
||||||
|
@ -107,11 +105,22 @@
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/butFF"
|
android:id="@+id/butFF"
|
||||||
android:layout_width="80dp"
|
android:layout_width="60dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_toRightOf="@id/butPlay"
|
android:layout_toRightOf="@id/butPlay"
|
||||||
android:background="?attr/borderless_button"
|
android:background="?attr/borderless_button"
|
||||||
android:src="?attr/av_fast_forward" />
|
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>
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
|
|
|
@ -79,8 +79,6 @@
|
||||||
android:layout_width="80dp"
|
android:layout_width="80dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_centerHorizontal="true"
|
android:layout_centerHorizontal="true"
|
||||||
android:layout_marginLeft="12dp"
|
|
||||||
android:layout_marginRight="12dp"
|
|
||||||
android:background="?attr/borderless_button"
|
android:background="?attr/borderless_button"
|
||||||
android:src="?attr/av_pause" />
|
android:src="?attr/av_pause" />
|
||||||
|
|
||||||
|
@ -99,6 +97,17 @@
|
||||||
android:layout_toRightOf="@id/butPlay"
|
android:layout_toRightOf="@id/butPlay"
|
||||||
android:background="?attr/borderless_button"
|
android:background="?attr/borderless_button"
|
||||||
android:src="?attr/av_fast_forward" />
|
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>
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
|
|
|
@ -1,6 +1,16 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
|
<string-array name="update_intervall_options">
|
||||||
|
<item>Manual</item>
|
||||||
|
<item>1 hour</item>
|
||||||
|
<item>2 hours</item>
|
||||||
|
<item>4 hours</item>
|
||||||
|
<item>8 hours</item>
|
||||||
|
<item>12 hours</item>
|
||||||
|
<item>24 hours</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<string-array name="update_intervall_values">
|
<string-array name="update_intervall_values">
|
||||||
<item>0</item>
|
<item>0</item>
|
||||||
<item>1</item>
|
<item>1</item>
|
||||||
|
@ -28,6 +38,50 @@
|
||||||
<item>80</item>
|
<item>80</item>
|
||||||
<item>100</item>
|
<item>100</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
<string-array name="playback_speed_values">
|
||||||
|
<item>1.0</item>
|
||||||
|
<item>1.05</item>
|
||||||
|
<item>1.10</item>
|
||||||
|
<item>1.15</item>
|
||||||
|
<item>1.20</item>
|
||||||
|
<item>1.25</item>
|
||||||
|
<item>1.30</item>
|
||||||
|
<item>1.35</item>
|
||||||
|
<item>1.40</item>
|
||||||
|
<item>1.45</item>
|
||||||
|
<item>1.50</item>
|
||||||
|
<item>1.55</item>
|
||||||
|
<item>1.60</item>
|
||||||
|
<item>1.65</item>
|
||||||
|
<item>1.70</item>
|
||||||
|
<item>1.75</item>
|
||||||
|
<item>1.80</item>
|
||||||
|
<item>1.85</item>
|
||||||
|
<item>1.90</item>
|
||||||
|
<item>1.95</item>
|
||||||
|
<item>2.00</item>
|
||||||
|
<item>2.10</item>
|
||||||
|
<item>2.20</item>
|
||||||
|
<item>2.30</item>
|
||||||
|
<item>2.40</item>
|
||||||
|
<item>2.50</item>
|
||||||
|
<item>2.60</item>
|
||||||
|
<item>2.70</item>
|
||||||
|
<item>2.80</item>
|
||||||
|
<item>2.90</item>
|
||||||
|
<item>3.00</item>
|
||||||
|
<item>3.10</item>
|
||||||
|
<item>3.20</item>
|
||||||
|
<item>3.30</item>
|
||||||
|
<item>3.40</item>
|
||||||
|
<item>3.50</item>
|
||||||
|
<item>3.60</item>
|
||||||
|
<item>3.70</item>
|
||||||
|
<item>3.80</item>
|
||||||
|
<item>3.90</item>
|
||||||
|
<item>4.00</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<string-array name="autodl_select_networks_default_entries">
|
<string-array name="autodl_select_networks_default_entries">
|
||||||
<item>N/A</item>
|
<item>N/A</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
@ -43,4 +97,5 @@
|
||||||
<item>1</item>
|
<item>1</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
|
@ -47,6 +47,8 @@
|
||||||
<string name="processing_label">Processing</string>
|
<string name="processing_label">Processing</string>
|
||||||
<string name="loading_label">Loading...</string>
|
<string name="loading_label">Loading...</string>
|
||||||
<string name="image_of_prefix">Image of:\u0020</string>
|
<string name="image_of_prefix">Image of:\u0020</string>
|
||||||
|
<string name="close_label">Close</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- 'Add Feed' Activity labels -->
|
<!-- 'Add Feed' Activity labels -->
|
||||||
<string name="feedurl_label">Feed URL</string>
|
<string name="feedurl_label">Feed URL</string>
|
||||||
|
@ -144,6 +146,12 @@
|
||||||
<string name="flattr_click_success">Successfully flattred this thing!</string>
|
<string name="flattr_click_success">Successfully flattred this thing!</string>
|
||||||
<string name="flattring_label">Flattring</string>
|
<string name="flattring_label">Flattring</string>
|
||||||
|
|
||||||
|
<!-- Variable Speed -->
|
||||||
|
<string name="download_plugin_label">Download Plugin</string>
|
||||||
|
<string name="no_playback_plugin_title">Plugin Not Installed</string>
|
||||||
|
<string name="no_playback_plugin_msg">For variable speed playback to work, a third party library must be installed.\n\nTap \'Download Plugin\' to download a free plugin from the Play Store\n\nAny problems found using this plugin are not the responsibility of AntennaPod and should be reported to the plugin owner.</string>
|
||||||
|
<string name="set_playback_speed_label">Playback Speeds</string>
|
||||||
|
|
||||||
<!-- Empty list labels -->
|
<!-- Empty list labels -->
|
||||||
<string name="no_items_label">There are no items in this list.</string>
|
<string name="no_items_label">There are no items in this list.</string>
|
||||||
<string name="no_feeds_label">You haven\'t subscribed to any feeds yet.</string>
|
<string name="no_feeds_label">You haven\'t subscribed to any feeds yet.</string>
|
||||||
|
@ -188,6 +196,8 @@
|
||||||
<string name="pref_update_interval_hours_plural">hours</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_singular">hour</string>
|
||||||
<string name="pref_update_interval_hours_manual">Manual</string>
|
<string name="pref_update_interval_hours_manual">Manual</string>
|
||||||
|
<string name="pref_playback_speed_title">Playback Speeds</string>
|
||||||
|
<string name="pref_playback_speed_sum">Customize the speeds available for variable speed audio playback</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- Search -->
|
<!-- Search -->
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
android:key="prefFollowQueue"
|
android:key="prefFollowQueue"
|
||||||
android:summary="@string/pref_followQueue_sum"
|
android:summary="@string/pref_followQueue_sum"
|
||||||
android:title="@string/pref_followQueue_title" />
|
android:title="@string/pref_followQueue_title" />
|
||||||
|
<Preference
|
||||||
|
android:key="prefPlaybackSpeedLauncher"
|
||||||
|
android:summary="@string/pref_playback_speed_sum"
|
||||||
|
android:title="@string/pref_playback_speed_title" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory android:title="@string/network_pref" >
|
<PreferenceCategory android:title="@string/network_pref" >
|
||||||
|
|
|
@ -12,7 +12,9 @@ import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
|
import android.view.View.OnLongClickListener;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Button;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView.ScaleType;
|
import android.widget.ImageView.ScaleType;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
@ -22,11 +24,14 @@ import de.danoeh.antennapod.AppConfig;
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.adapter.ChapterListAdapter;
|
import de.danoeh.antennapod.adapter.ChapterListAdapter;
|
||||||
import de.danoeh.antennapod.asynctask.ImageLoader;
|
import de.danoeh.antennapod.asynctask.ImageLoader;
|
||||||
|
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
|
||||||
import de.danoeh.antennapod.feed.Chapter;
|
import de.danoeh.antennapod.feed.Chapter;
|
||||||
import de.danoeh.antennapod.feed.MediaType;
|
import de.danoeh.antennapod.feed.MediaType;
|
||||||
import de.danoeh.antennapod.feed.SimpleChapter;
|
import de.danoeh.antennapod.feed.SimpleChapter;
|
||||||
import de.danoeh.antennapod.fragment.CoverFragment;
|
import de.danoeh.antennapod.fragment.CoverFragment;
|
||||||
import de.danoeh.antennapod.fragment.ItemDescriptionFragment;
|
import de.danoeh.antennapod.fragment.ItemDescriptionFragment;
|
||||||
|
import de.danoeh.antennapod.preferences.UserPreferences;
|
||||||
|
import de.danoeh.antennapod.preferences.UserPreferences;
|
||||||
import de.danoeh.antennapod.service.PlaybackService;
|
import de.danoeh.antennapod.service.PlaybackService;
|
||||||
import de.danoeh.antennapod.util.playback.ExternalMedia;
|
import de.danoeh.antennapod.util.playback.ExternalMedia;
|
||||||
import de.danoeh.antennapod.util.playback.Playable;
|
import de.danoeh.antennapod.util.playback.Playable;
|
||||||
|
@ -56,6 +61,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
|
||||||
|
|
||||||
private TextView txtvTitle;
|
private TextView txtvTitle;
|
||||||
private TextView txtvFeed;
|
private TextView txtvFeed;
|
||||||
|
private Button butPlaybackSpeed;
|
||||||
private ImageButton butNavLeft;
|
private ImageButton butNavLeft;
|
||||||
private ImageButton butNavRight;
|
private ImageButton butNavRight;
|
||||||
|
|
||||||
|
@ -363,6 +369,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
|
||||||
txtvFeed = (TextView) findViewById(R.id.txtvFeed);
|
txtvFeed = (TextView) findViewById(R.id.txtvFeed);
|
||||||
butNavLeft = (ImageButton) findViewById(R.id.butNavLeft);
|
butNavLeft = (ImageButton) findViewById(R.id.butNavLeft);
|
||||||
butNavRight = (ImageButton) findViewById(R.id.butNavRight);
|
butNavRight = (ImageButton) findViewById(R.id.butNavRight);
|
||||||
|
butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed);
|
||||||
|
|
||||||
butNavLeft.setOnClickListener(new OnClickListener() {
|
butNavLeft.setOnClickListener(new OnClickListener() {
|
||||||
|
|
||||||
|
@ -390,6 +397,65 @@ public class AudioplayerActivity extends MediaplayerActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
butPlaybackSpeed.setOnClickListener(new OnClickListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (controller != null && controller.canSetPlaybackSpeed()) {
|
||||||
|
String[] availableSpeeds = UserPreferences
|
||||||
|
.getPlaybackSpeedArray();
|
||||||
|
String currentSpeed = UserPreferences.getPlaybackSpeed();
|
||||||
|
|
||||||
|
// Provide initial value in case the speed list has changed
|
||||||
|
// out from under us
|
||||||
|
// and our current speed isn't in the new list
|
||||||
|
String newSpeed;
|
||||||
|
if (availableSpeeds.length > 0) {
|
||||||
|
newSpeed = availableSpeeds[0];
|
||||||
|
} else {
|
||||||
|
newSpeed = "1.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < availableSpeeds.length; i++) {
|
||||||
|
if (availableSpeeds[i].equals(currentSpeed)) {
|
||||||
|
if (i == availableSpeeds.length - 1) {
|
||||||
|
newSpeed = availableSpeeds[0];
|
||||||
|
} else {
|
||||||
|
newSpeed = availableSpeeds[i + 1];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UserPreferences.setPlaybackSpeed(newSpeed);
|
||||||
|
controller.setPlaybackSpeed(Float.parseFloat(newSpeed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
butPlaybackSpeed.setOnLongClickListener(new OnLongClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onLongClick(View v) {
|
||||||
|
VariableSpeedDialog.showDialog(AudioplayerActivity.this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPlaybackSpeedChange() {
|
||||||
|
super.onPlaybackSpeedChange();
|
||||||
|
updateButPlaybackSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateButPlaybackSpeed() {
|
||||||
|
if (controller == null
|
||||||
|
|| (controller.getCurrentPlaybackSpeedMultiplier() == -1)) {
|
||||||
|
butPlaybackSpeed.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
butPlaybackSpeed.setVisibility(View.VISIBLE);
|
||||||
|
butPlaybackSpeed.setText(UserPreferences.getPlaybackSpeed());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -421,7 +487,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
|
||||||
((AudioplayerContentFragment) currentlyShownFragment)
|
((AudioplayerContentFragment) currentlyShownFragment)
|
||||||
.onDataSetChanged(media);
|
.onDataSetChanged(media);
|
||||||
}
|
}
|
||||||
|
updateButPlaybackSpeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyMediaPositionChanged() {
|
public void notifyMediaPositionChanged() {
|
||||||
|
|
|
@ -129,10 +129,19 @@ public abstract class MediaplayerActivity extends ActionBarActivity
|
||||||
public void onPlaybackEnd() {
|
public void onPlaybackEnd() {
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPlaybackSpeedChange() {
|
||||||
|
MediaplayerActivity.this.onPlaybackSpeedChange();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void onPlaybackSpeedChange() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected void onServiceQueried() {
|
protected void onServiceQueried() {
|
||||||
supportInvalidateOptionsMenu();
|
supportInvalidateOptionsMenu();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import de.danoeh.antennapod.AppConfig;
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.asynctask.FlattrClickWorker;
|
import de.danoeh.antennapod.asynctask.FlattrClickWorker;
|
||||||
import de.danoeh.antennapod.asynctask.OpmlExportWorker;
|
import de.danoeh.antennapod.asynctask.OpmlExportWorker;
|
||||||
|
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
|
||||||
import de.danoeh.antennapod.preferences.UserPreferences;
|
import de.danoeh.antennapod.preferences.UserPreferences;
|
||||||
import de.danoeh.antennapod.util.flattr.FlattrUtils;
|
import de.danoeh.antennapod.util.flattr.FlattrUtils;
|
||||||
|
|
||||||
|
@ -41,6 +42,7 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
|
||||||
private static final String PREF_ABOUT = "prefAbout";
|
private static final String PREF_ABOUT = "prefAbout";
|
||||||
private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir";
|
private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir";
|
||||||
private static final String AUTO_DL_PREF_SCREEN = "prefAutoDownloadSettings";
|
private static final String AUTO_DL_PREF_SCREEN = "prefAutoDownloadSettings";
|
||||||
|
private static final String PREF_PLAYBACK_SPEED_LAUNCHER = "prefPlaybackSpeedLauncher";
|
||||||
|
|
||||||
private CheckBoxPreference[] selectedNetworks;
|
private CheckBoxPreference[] selectedNetworks;
|
||||||
|
|
||||||
|
@ -156,6 +158,14 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
findPreference(PREF_PLAYBACK_SPEED_LAUNCHER)
|
||||||
|
.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
VariableSpeedDialog.showDialog(PreferenceActivity.this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
buildUpdateIntervalPreference();
|
buildUpdateIntervalPreference();
|
||||||
buildAutodownloadSelectedNetworsPreference();
|
buildAutodownloadSelectedNetworsPreference();
|
||||||
setSelectedNetworksEnabled(UserPreferences
|
setSelectedNetworksEnabled(UserPreferences
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
package de.danoeh.antennapod.dialog;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import de.danoeh.antennapod.R;
|
||||||
|
import de.danoeh.antennapod.preferences.UserPreferences;
|
||||||
|
|
||||||
|
public class VariableSpeedDialog {
|
||||||
|
private VariableSpeedDialog() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showDialog(final Context context) {
|
||||||
|
if (com.aocate.media.MediaPlayer.isPrestoLibraryInstalled(context)) {
|
||||||
|
showSpeedSelectorDialog(context);
|
||||||
|
} else {
|
||||||
|
showGetPluginDialog(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void showGetPluginDialog(final Context context) {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||||
|
builder.setTitle(R.string.no_playback_plugin_title);
|
||||||
|
builder.setMessage(R.string.no_playback_plugin_msg);
|
||||||
|
builder.setNegativeButton(R.string.close_label, null);
|
||||||
|
builder.setPositiveButton(R.string.download_plugin_label,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
Intent playStoreIntent = new Intent(
|
||||||
|
Intent.ACTION_VIEW,
|
||||||
|
Uri.parse("market://details?id=com.falconware.prestissimo"));
|
||||||
|
context.startActivity(playStoreIntent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.create().show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void showSpeedSelectorDialog(final Context context) {
|
||||||
|
final String[] speedValues = context.getResources().getStringArray(
|
||||||
|
R.array.playback_speed_values);
|
||||||
|
// According to Java spec these get initialized to false on creation
|
||||||
|
final boolean[] speedChecked = new boolean[speedValues.length];
|
||||||
|
|
||||||
|
// Build the "isChecked" array so that multiChoice dialog is
|
||||||
|
// populated correctly
|
||||||
|
List<String> selectedSpeedList = Arrays.asList(UserPreferences
|
||||||
|
.getPlaybackSpeedArray());
|
||||||
|
for (int i = 0; i < speedValues.length; i++) {
|
||||||
|
speedChecked[i] = selectedSpeedList.contains(speedValues[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||||
|
builder.setTitle(R.string.set_playback_speed_label);
|
||||||
|
builder.setMultiChoiceItems(R.array.playback_speed_values,
|
||||||
|
speedChecked, new DialogInterface.OnMultiChoiceClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which,
|
||||||
|
boolean isChecked) {
|
||||||
|
speedChecked[which] = isChecked;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
builder.setNegativeButton(android.R.string.cancel, null);
|
||||||
|
builder.setPositiveButton(android.R.string.ok,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
int choiceCount = 0;
|
||||||
|
for (int i = 0; i < speedChecked.length; i++) {
|
||||||
|
if (speedChecked[i]) {
|
||||||
|
choiceCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String[] newSpeedValues = new String[choiceCount];
|
||||||
|
int newSpeedIndex = 0;
|
||||||
|
for (int i = 0; i < speedChecked.length; i++) {
|
||||||
|
if (speedChecked[i]) {
|
||||||
|
newSpeedValues[newSpeedIndex++] = speedValues[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UserPreferences.setPlaybackSpeedArray(newSpeedValues);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.create().show();
|
||||||
|
}
|
||||||
|
}
|
|
@ -173,6 +173,12 @@ public class ExternalPlayerFragment extends Fragment {
|
||||||
.newOnPlayButtonClickListener());
|
.newOnPlayButtonClickListener());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPlaybackSpeedChange() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,13 @@ package de.danoeh.antennapod.preferences;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
|
@ -41,11 +45,13 @@ public class UserPreferences implements
|
||||||
public static final String PREF_ENABLE_AUTODL_WIFI_FILTER = "prefEnableAutoDownloadWifiFilter";
|
public static final String PREF_ENABLE_AUTODL_WIFI_FILTER = "prefEnableAutoDownloadWifiFilter";
|
||||||
private static final String PREF_AUTODL_SELECTED_NETWORKS = "prefAutodownloadSelectedNetworks";
|
private static final String PREF_AUTODL_SELECTED_NETWORKS = "prefAutodownloadSelectedNetworks";
|
||||||
public static final String PREF_EPISODE_CACHE_SIZE = "prefEpisodeCacheSize";
|
public static final String PREF_EPISODE_CACHE_SIZE = "prefEpisodeCacheSize";
|
||||||
|
private static final String PREF_PLAYBACK_SPEED = "prefPlaybackSpeed";
|
||||||
|
private static final String PREF_PLAYBACK_SPEED_ARRAY = "prefPlaybackSpeedArray";
|
||||||
|
|
||||||
private static int EPISODE_CACHE_SIZE_UNLIMITED = -1;
|
private static int EPISODE_CACHE_SIZE_UNLIMITED = -1;
|
||||||
|
|
||||||
private static UserPreferences instance;
|
private static UserPreferences instance;
|
||||||
private Context context;
|
private final Context context;
|
||||||
|
|
||||||
// Preferences
|
// Preferences
|
||||||
private boolean pauseOnHeadsetDisconnect;
|
private boolean pauseOnHeadsetDisconnect;
|
||||||
|
@ -60,6 +66,8 @@ public class UserPreferences implements
|
||||||
private boolean enableAutodownloadWifiFilter;
|
private boolean enableAutodownloadWifiFilter;
|
||||||
private String[] autodownloadSelectedNetworks;
|
private String[] autodownloadSelectedNetworks;
|
||||||
private int episodeCacheSize;
|
private int episodeCacheSize;
|
||||||
|
private String playbackSpeed;
|
||||||
|
private String[] playbackSpeedArray;
|
||||||
|
|
||||||
private UserPreferences(Context context) {
|
private UserPreferences(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
@ -83,6 +91,7 @@ public class UserPreferences implements
|
||||||
createNoMediaFile();
|
createNoMediaFile();
|
||||||
PreferenceManager.getDefaultSharedPreferences(context)
|
PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
.registerOnSharedPreferenceChangeListener(instance);
|
.registerOnSharedPreferenceChangeListener(instance);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadPreferences() {
|
private void loadPreferences() {
|
||||||
|
@ -108,6 +117,9 @@ public class UserPreferences implements
|
||||||
episodeCacheSize = readEpisodeCacheSize(sp.getString(
|
episodeCacheSize = readEpisodeCacheSize(sp.getString(
|
||||||
PREF_EPISODE_CACHE_SIZE, "20"));
|
PREF_EPISODE_CACHE_SIZE, "20"));
|
||||||
enableAutodownload = sp.getBoolean(PREF_ENABLE_AUTODL, false);
|
enableAutodownload = sp.getBoolean(PREF_ENABLE_AUTODL, false);
|
||||||
|
playbackSpeed = sp.getString(PREF_PLAYBACK_SPEED, "1.0");
|
||||||
|
playbackSpeedArray = readPlaybackSpeedArray(sp.getString(
|
||||||
|
PREF_PLAYBACK_SPEED_ARRAY, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readThemeValue(String valueFromPrefs) {
|
private int readThemeValue(String valueFromPrefs) {
|
||||||
|
@ -135,6 +147,36 @@ public class UserPreferences implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String[] readPlaybackSpeedArray(String valueFromPrefs) {
|
||||||
|
String[] selectedSpeeds = null;
|
||||||
|
// If this preference hasn't been set yet, return the default options
|
||||||
|
if (valueFromPrefs == null) {
|
||||||
|
String[] allSpeeds = context.getResources().getStringArray(
|
||||||
|
R.array.playback_speed_values);
|
||||||
|
List<String> speedList = new LinkedList<String>();
|
||||||
|
for (String speedStr : allSpeeds) {
|
||||||
|
float speed = Float.parseFloat(speedStr);
|
||||||
|
if (speed < 2.0001 && speed * 10 % 1 == 0) {
|
||||||
|
speedList.add(speedStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selectedSpeeds = speedList.toArray(new String[speedList.size()]);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
JSONArray jsonArray = new JSONArray(valueFromPrefs);
|
||||||
|
selectedSpeeds = new String[jsonArray.length()];
|
||||||
|
for (int i = 0; i < jsonArray.length(); i++) {
|
||||||
|
selectedSpeeds[i] = jsonArray.getString(i);
|
||||||
|
}
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.e(TAG,
|
||||||
|
"Got JSON error when trying to get speeds from JSONArray");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return selectedSpeeds;
|
||||||
|
}
|
||||||
|
|
||||||
private static void instanceAvailable() {
|
private static void instanceAvailable() {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
|
@ -196,6 +238,16 @@ public class UserPreferences implements
|
||||||
return EPISODE_CACHE_SIZE_UNLIMITED;
|
return EPISODE_CACHE_SIZE_UNLIMITED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getPlaybackSpeed() {
|
||||||
|
instanceAvailable();
|
||||||
|
return instance.playbackSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] getPlaybackSpeedArray() {
|
||||||
|
instanceAvailable();
|
||||||
|
return instance.playbackSpeedArray;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the capacity of the episode cache. This method will return the
|
* 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
|
* negative integer EPISODE_CACHE_SIZE_UNLIMITED if the cache size is set to
|
||||||
|
@ -250,9 +302,29 @@ public class UserPreferences implements
|
||||||
PREF_EPISODE_CACHE_SIZE, "20"));
|
PREF_EPISODE_CACHE_SIZE, "20"));
|
||||||
} else if (key.equals(PREF_ENABLE_AUTODL)) {
|
} else if (key.equals(PREF_ENABLE_AUTODL)) {
|
||||||
enableAutodownload = sp.getBoolean(PREF_ENABLE_AUTODL, false);
|
enableAutodownload = sp.getBoolean(PREF_ENABLE_AUTODL, false);
|
||||||
|
} else if (key.equals(PREF_PLAYBACK_SPEED)) {
|
||||||
|
playbackSpeed = sp.getString(PREF_PLAYBACK_SPEED, "1.0");
|
||||||
|
} else if (key.equals(PREF_PLAYBACK_SPEED_ARRAY)) {
|
||||||
|
playbackSpeedArray = readPlaybackSpeedArray(sp.getString(
|
||||||
|
PREF_PLAYBACK_SPEED_ARRAY, null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setPlaybackSpeed(String speed) {
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(instance.context).edit()
|
||||||
|
.putString(PREF_PLAYBACK_SPEED, speed).apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setPlaybackSpeedArray(String[] speeds) {
|
||||||
|
JSONArray jsonArray = new JSONArray();
|
||||||
|
for (String speed : speeds) {
|
||||||
|
jsonArray.put(speed);
|
||||||
|
}
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(instance.context).edit()
|
||||||
|
.putString(PREF_PLAYBACK_SPEED_ARRAY, jsonArray.toString())
|
||||||
|
.apply();
|
||||||
|
}
|
||||||
|
|
||||||
public static void setAutodownloadSelectedNetworks(Context context,
|
public static void setAutodownloadSelectedNetworks(Context context,
|
||||||
String[] value) {
|
String[] value) {
|
||||||
SharedPreferences.Editor editor = PreferenceManager
|
SharedPreferences.Editor editor = PreferenceManager
|
||||||
|
|
|
@ -45,9 +45,13 @@ import de.danoeh.antennapod.storage.DBTasks;
|
||||||
import de.danoeh.antennapod.storage.DBWriter;
|
import de.danoeh.antennapod.storage.DBWriter;
|
||||||
import de.danoeh.antennapod.util.BitmapDecoder;
|
import de.danoeh.antennapod.util.BitmapDecoder;
|
||||||
import de.danoeh.antennapod.util.QueueAccess;
|
import de.danoeh.antennapod.util.QueueAccess;
|
||||||
|
import de.danoeh.antennapod.util.DuckType;
|
||||||
import de.danoeh.antennapod.util.flattr.FlattrUtils;
|
import de.danoeh.antennapod.util.flattr.FlattrUtils;
|
||||||
|
import de.danoeh.antennapod.util.playback.AudioPlayer;
|
||||||
|
import de.danoeh.antennapod.util.playback.IPlayer;
|
||||||
import de.danoeh.antennapod.util.playback.Playable;
|
import de.danoeh.antennapod.util.playback.Playable;
|
||||||
import de.danoeh.antennapod.util.playback.Playable.PlayableException;
|
import de.danoeh.antennapod.util.playback.Playable.PlayableException;
|
||||||
|
import de.danoeh.antennapod.util.playback.VideoPlayer;
|
||||||
import de.danoeh.antennapod.util.playback.PlaybackController;
|
import de.danoeh.antennapod.util.playback.PlaybackController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -119,6 +123,11 @@ public class PlaybackService extends Service {
|
||||||
*/
|
*/
|
||||||
public static final int NOTIFICATION_TYPE_PLAYBACK_END = 7;
|
public static final int NOTIFICATION_TYPE_PLAYBACK_END = 7;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Playback speed has changed
|
||||||
|
* */
|
||||||
|
public static final int NOTIFICATION_TYPE_PLAYBACK_SPEED_CHANGE = 8;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returned by getPositionSafe() or getDurationSafe() if the playbackService
|
* Returned by getPositionSafe() or getDurationSafe() if the playbackService
|
||||||
* is in an invalid state.
|
* is in an invalid state.
|
||||||
|
@ -132,13 +141,12 @@ public class PlaybackService extends Service {
|
||||||
|
|
||||||
private static final int NOTIFICATION_ID = 1;
|
private static final int NOTIFICATION_ID = 1;
|
||||||
|
|
||||||
|
private volatile IPlayer player;
|
||||||
|
private RemoteControlClient remoteControlClient;
|
||||||
private AudioManager audioManager;
|
private AudioManager audioManager;
|
||||||
private ComponentName mediaButtonReceiver;
|
private ComponentName mediaButtonReceiver;
|
||||||
|
|
||||||
private MediaPlayer player;
|
private volatile Playable media;
|
||||||
private RemoteControlClient remoteControlClient;
|
|
||||||
|
|
||||||
private Playable media;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if media should be streamed (Extracted from Intent Extra) .
|
* True if media should be streamed (Extracted from Intent Extra) .
|
||||||
|
@ -252,7 +260,6 @@ public class PlaybackService extends Service {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
dbLoaderExecutor = Executors.newSingleThreadExecutor();
|
dbLoaderExecutor = Executors.newSingleThreadExecutor();
|
||||||
player = createMediaPlayer();
|
|
||||||
|
|
||||||
mediaButtonReceiver = new ComponentName(getPackageName(),
|
mediaButtonReceiver = new ComponentName(getPackageName(),
|
||||||
MediaButtonReceiver.class.getName());
|
MediaButtonReceiver.class.getName());
|
||||||
|
@ -273,18 +280,39 @@ public class PlaybackService extends Service {
|
||||||
loadQueue();
|
loadQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private MediaPlayer createMediaPlayer() {
|
private IPlayer createMediaPlayer() {
|
||||||
return createMediaPlayer(new MediaPlayer());
|
IPlayer player;
|
||||||
|
if (media == null || media.getMediaType() == MediaType.VIDEO) {
|
||||||
|
player = new VideoPlayer();
|
||||||
|
} else {
|
||||||
|
player = new AudioPlayer(this);
|
||||||
|
}
|
||||||
|
return createMediaPlayer(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MediaPlayer createMediaPlayer(MediaPlayer mp) {
|
private IPlayer createMediaPlayer(IPlayer mp) {
|
||||||
if (mp != null) {
|
if (mp != null && media != null) {
|
||||||
mp.setOnPreparedListener(preparedListener);
|
if (media.getMediaType() == MediaType.AUDIO) {
|
||||||
mp.setOnCompletionListener(completionListener);
|
((AudioPlayer) mp).setOnPreparedListener(audioPreparedListener);
|
||||||
mp.setOnSeekCompleteListener(onSeekCompleteListener);
|
((AudioPlayer) mp)
|
||||||
mp.setOnErrorListener(onErrorListener);
|
.setOnCompletionListener(audioCompletionListener);
|
||||||
mp.setOnBufferingUpdateListener(onBufferingUpdateListener);
|
((AudioPlayer) mp)
|
||||||
mp.setOnInfoListener(onInfoListener);
|
.setOnSeekCompleteListener(audioSeekCompleteListener);
|
||||||
|
((AudioPlayer) mp).setOnErrorListener(audioErrorListener);
|
||||||
|
((AudioPlayer) mp)
|
||||||
|
.setOnBufferingUpdateListener(audioBufferingUpdateListener);
|
||||||
|
((AudioPlayer) mp).setOnInfoListener(audioInfoListener);
|
||||||
|
} else {
|
||||||
|
((VideoPlayer) mp).setOnPreparedListener(videoPreparedListener);
|
||||||
|
((VideoPlayer) mp)
|
||||||
|
.setOnCompletionListener(videoCompletionListener);
|
||||||
|
((VideoPlayer) mp)
|
||||||
|
.setOnSeekCompleteListener(videoSeekCompleteListener);
|
||||||
|
((VideoPlayer) mp).setOnErrorListener(videoErrorListener);
|
||||||
|
((VideoPlayer) mp)
|
||||||
|
.setOnBufferingUpdateListener(videoBufferingUpdateListener);
|
||||||
|
((VideoPlayer) mp).setOnInfoListener(videoInfoListener);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return mp;
|
return mp;
|
||||||
}
|
}
|
||||||
|
@ -568,6 +596,7 @@ public class PlaybackService extends Service {
|
||||||
Log.d(TAG, "Setting up media player");
|
Log.d(TAG, "Setting up media player");
|
||||||
try {
|
try {
|
||||||
MediaType mediaType = media.getMediaType();
|
MediaType mediaType = media.getMediaType();
|
||||||
|
player = createMediaPlayer();
|
||||||
if (mediaType == MediaType.AUDIO) {
|
if (mediaType == MediaType.AUDIO) {
|
||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Mime type is audio");
|
Log.d(TAG, "Mime type is audio");
|
||||||
|
@ -662,9 +691,22 @@ public class PlaybackService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MediaPlayer.OnPreparedListener preparedListener = new MediaPlayer.OnPreparedListener() {
|
private final com.aocate.media.MediaPlayer.OnPreparedListener audioPreparedListener = new com.aocate.media.MediaPlayer.OnPreparedListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onPrepared(MediaPlayer mp) {
|
public void onPrepared(com.aocate.media.MediaPlayer mp) {
|
||||||
|
genericOnPrepared(mp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final android.media.MediaPlayer.OnPreparedListener videoPreparedListener = new android.media.MediaPlayer.OnPreparedListener() {
|
||||||
|
@Override
|
||||||
|
public void onPrepared(android.media.MediaPlayer mp) {
|
||||||
|
genericOnPrepared(mp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final void genericOnPrepared(Object inObj) {
|
||||||
|
IPlayer mp = DuckType.coerce(inObj).to(IPlayer.class);
|
||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Resource prepared");
|
Log.d(TAG, "Resource prepared");
|
||||||
mp.seekTo(media.getPosition());
|
mp.seekTo(media.getPosition());
|
||||||
|
@ -699,23 +741,43 @@ public class PlaybackService extends Service {
|
||||||
play();
|
play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final com.aocate.media.MediaPlayer.OnSeekCompleteListener audioSeekCompleteListener = new com.aocate.media.MediaPlayer.OnSeekCompleteListener() {
|
||||||
|
@Override
|
||||||
|
public void onSeekComplete(com.aocate.media.MediaPlayer mp) {
|
||||||
|
genericSeekCompleteListener();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private MediaPlayer.OnSeekCompleteListener onSeekCompleteListener = new MediaPlayer.OnSeekCompleteListener() {
|
private final android.media.MediaPlayer.OnSeekCompleteListener videoSeekCompleteListener = new android.media.MediaPlayer.OnSeekCompleteListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSeekComplete(MediaPlayer mp) {
|
public void onSeekComplete(android.media.MediaPlayer mp) {
|
||||||
|
genericSeekCompleteListener();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final void genericSeekCompleteListener() {
|
||||||
if (status == PlayerStatus.SEEKING) {
|
if (status == PlayerStatus.SEEKING) {
|
||||||
setStatus(statusBeforeSeek);
|
setStatus(statusBeforeSeek);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final com.aocate.media.MediaPlayer.OnInfoListener audioInfoListener = new com.aocate.media.MediaPlayer.OnInfoListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onInfo(com.aocate.media.MediaPlayer mp, int what,
|
||||||
|
int extra) {
|
||||||
|
return genericInfoListener(what);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private MediaPlayer.OnInfoListener onInfoListener = new MediaPlayer.OnInfoListener() {
|
private final android.media.MediaPlayer.OnInfoListener videoInfoListener = new android.media.MediaPlayer.OnInfoListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onInfo(MediaPlayer mp, int what, int extra) {
|
public boolean onInfo(android.media.MediaPlayer mp, int what, int extra) {
|
||||||
|
return genericInfoListener(what);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private boolean genericInfoListener(int what) {
|
||||||
switch (what) {
|
switch (what) {
|
||||||
case MediaPlayer.MEDIA_INFO_BUFFERING_START:
|
case MediaPlayer.MEDIA_INFO_BUFFERING_START:
|
||||||
sendNotificationBroadcast(NOTIFICATION_TYPE_BUFFER_START, 0);
|
sendNotificationBroadcast(NOTIFICATION_TYPE_BUFFER_START, 0);
|
||||||
|
@ -727,14 +789,26 @@ public class PlaybackService extends Service {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final com.aocate.media.MediaPlayer.OnErrorListener audioErrorListener = new com.aocate.media.MediaPlayer.OnErrorListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onError(com.aocate.media.MediaPlayer mp, int what,
|
||||||
|
int extra) {
|
||||||
|
return genericOnError(mp, what, extra);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private MediaPlayer.OnErrorListener onErrorListener = new MediaPlayer.OnErrorListener() {
|
private final android.media.MediaPlayer.OnErrorListener videoErrorListener = new android.media.MediaPlayer.OnErrorListener() {
|
||||||
private static final String TAG = "PlaybackService.onErrorListener";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onError(MediaPlayer mp, int what, int extra) {
|
public boolean onError(android.media.MediaPlayer mp, int what, int extra) {
|
||||||
Log.w(TAG, "An error has occured: " + what);
|
return genericOnError(mp, what, extra);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private boolean genericOnError(Object inObj, int what, int extra) {
|
||||||
|
final String TAG = "PlaybackService.onErrorListener";
|
||||||
|
Log.w(TAG, "An error has occured: " + what + " " + extra);
|
||||||
|
IPlayer mp = DuckType.coerce(inObj).to(IPlayer.class);
|
||||||
if (mp.isPlaying()) {
|
if (mp.isPlaying()) {
|
||||||
pause(true, true);
|
pause(true, true);
|
||||||
}
|
}
|
||||||
|
@ -743,25 +817,44 @@ public class PlaybackService extends Service {
|
||||||
stopSelf();
|
stopSelf();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final com.aocate.media.MediaPlayer.OnCompletionListener audioCompletionListener = new com.aocate.media.MediaPlayer.OnCompletionListener() {
|
||||||
|
@Override
|
||||||
|
public void onCompletion(com.aocate.media.MediaPlayer mp) {
|
||||||
|
genericOnCompletion();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private MediaPlayer.OnCompletionListener completionListener = new MediaPlayer.OnCompletionListener() {
|
private final android.media.MediaPlayer.OnCompletionListener videoCompletionListener = new android.media.MediaPlayer.OnCompletionListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCompletion(MediaPlayer mp) {
|
public void onCompletion(android.media.MediaPlayer mp) {
|
||||||
|
genericOnCompletion();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private void genericOnCompletion() {
|
||||||
endPlayback(true);
|
endPlayback(true);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
private MediaPlayer.OnBufferingUpdateListener onBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() {
|
|
||||||
|
|
||||||
|
private final com.aocate.media.MediaPlayer.OnBufferingUpdateListener audioBufferingUpdateListener = new com.aocate.media.MediaPlayer.OnBufferingUpdateListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onBufferingUpdate(MediaPlayer mp, int percent) {
|
public void onBufferingUpdate(com.aocate.media.MediaPlayer mp,
|
||||||
sendNotificationBroadcast(NOTIFICATION_TYPE_BUFFER_UPDATE, percent);
|
int percent) {
|
||||||
|
genericOnBufferingUpdate(percent);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private final android.media.MediaPlayer.OnBufferingUpdateListener videoBufferingUpdateListener = new android.media.MediaPlayer.OnBufferingUpdateListener() {
|
||||||
|
@Override
|
||||||
|
public void onBufferingUpdate(android.media.MediaPlayer mp, int percent) {
|
||||||
|
genericOnBufferingUpdate(percent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private void genericOnBufferingUpdate(int percent) {
|
||||||
|
sendNotificationBroadcast(NOTIFICATION_TYPE_BUFFER_UPDATE, percent);
|
||||||
|
}
|
||||||
|
|
||||||
private void endPlayback(boolean playNextEpisode) {
|
private void endPlayback(boolean playNextEpisode) {
|
||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Playback ended");
|
Log.d(TAG, "Playback ended");
|
||||||
|
@ -938,6 +1031,7 @@ public class PlaybackService extends Service {
|
||||||
Log.d(TAG, "Resuming/Starting playback");
|
Log.d(TAG, "Resuming/Starting playback");
|
||||||
writePlaybackPreferences();
|
writePlaybackPreferences();
|
||||||
|
|
||||||
|
setSpeed(Float.parseFloat(UserPreferences.getPlaybackSpeed()));
|
||||||
player.start();
|
player.start();
|
||||||
if (status != PlayerStatus.PAUSED) {
|
if (status != PlayerStatus.PAUSED) {
|
||||||
player.seekTo((int) media.getPosition());
|
player.seekTo((int) media.getPosition());
|
||||||
|
@ -1473,7 +1567,7 @@ public class PlaybackService extends Service {
|
||||||
return media;
|
return media;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MediaPlayer getPlayer() {
|
public IPlayer getPlayer() {
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1486,6 +1580,53 @@ public class PlaybackService extends Service {
|
||||||
postStatusUpdateIntent();
|
postStatusUpdateIntent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canSetSpeed() {
|
||||||
|
if (player != null && media != null && media.getMediaType() == MediaType.AUDIO) {
|
||||||
|
return ((AudioPlayer) player).canSetSpeed();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canSetPitch() {
|
||||||
|
if (player != null && media != null && media.getMediaType() == MediaType.AUDIO) {
|
||||||
|
return ((AudioPlayer) player).canSetPitch();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSpeed(float speed) {
|
||||||
|
if (media != null && media.getMediaType() == MediaType.AUDIO) {
|
||||||
|
AudioPlayer audioPlayer = (AudioPlayer) player;
|
||||||
|
if (audioPlayer.canSetSpeed()) {
|
||||||
|
audioPlayer.setPlaybackSpeed((float) 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 != null && media.getMediaType() == MediaType.AUDIO) {
|
||||||
|
AudioPlayer audioPlayer = (AudioPlayer) player;
|
||||||
|
if (audioPlayer.canSetPitch()) {
|
||||||
|
audioPlayer.setPlaybackPitch((float) pitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float 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
|
* call getDuration() on mediaplayer or return INVALID_TIME if player is in
|
||||||
* an invalid state. This method should be used instead of calling
|
* an invalid state. This method should be used instead of calling
|
||||||
|
|
|
@ -800,8 +800,9 @@ public class DownloadService extends Service {
|
||||||
media.setFile_url(request.getDestination());
|
media.setFile_url(request.getDestination());
|
||||||
|
|
||||||
// Get duration
|
// Get duration
|
||||||
MediaPlayer mediaplayer = new MediaPlayer();
|
MediaPlayer mediaplayer = null;
|
||||||
try {
|
try {
|
||||||
|
mediaplayer = new MediaPlayer();
|
||||||
mediaplayer.setDataSource(media.getFile_url());
|
mediaplayer.setDataSource(media.getFile_url());
|
||||||
mediaplayer.prepare();
|
mediaplayer.prepare();
|
||||||
media.setDuration(mediaplayer.getDuration());
|
media.setDuration(mediaplayer.getDuration());
|
||||||
|
@ -810,9 +811,14 @@ public class DownloadService extends Service {
|
||||||
mediaplayer.reset();
|
mediaplayer.reset();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
// Thrown by MediaPlayer initialization on some devices
|
||||||
|
e.printStackTrace();
|
||||||
} finally {
|
} finally {
|
||||||
|
if (mediaplayer != null) {
|
||||||
mediaplayer.release();
|
mediaplayer.release();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (media.getItem().getChapters() == null) {
|
if (media.getItem().getChapters() == null) {
|
||||||
ChapterUtils.loadChaptersFromFileUrl(media);
|
ChapterUtils.loadChaptersFromFileUrl(media);
|
||||||
|
|
|
@ -441,13 +441,7 @@ public final class DBTasks {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (FeedItem item : delete) {
|
for (FeedItem item : delete) {
|
||||||
try {
|
DBWriter.deleteFeedMediaOfItem(context, item.getId());
|
||||||
DBWriter.deleteFeedMediaOfItem(context, item.getId()).get();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int counter = delete.size();
|
int counter = delete.size();
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
/* Adapted from: http://thinking-in-code.blogspot.com/2008/11/duck-typing-in-java-using-dynamic.html */
|
||||||
|
|
||||||
|
package de.danoeh.antennapod.util;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows "duck typing" or dynamic invocation based on method signature rather
|
||||||
|
* than type hierarchy. In other words, rather than checking whether something
|
||||||
|
* IS-a duck, check whether it WALKS-like-a duck or QUACKS-like a duck.
|
||||||
|
*
|
||||||
|
* To use first use the coerce static method to indicate the object you want to
|
||||||
|
* do Duck Typing for, then specify an interface to the to method which you want
|
||||||
|
* to coerce the type to, e.g:
|
||||||
|
*
|
||||||
|
* public interface Foo { void aMethod(); } class Bar { ... public void
|
||||||
|
* aMethod() { ... } ... } Bar bar = ...; Foo foo =
|
||||||
|
* DuckType.coerce(bar).to(Foo.class); foo.aMethod();
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DuckType {
|
||||||
|
|
||||||
|
private final Object objectToCoerce;
|
||||||
|
|
||||||
|
private DuckType(Object objectToCoerce) {
|
||||||
|
this.objectToCoerce = objectToCoerce;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CoercedProxy implements InvocationHandler {
|
||||||
|
@Override
|
||||||
|
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||||
|
Method delegateMethod = findMethodBySignature(method);
|
||||||
|
assert delegateMethod != null;
|
||||||
|
return delegateMethod.invoke(DuckType.this.objectToCoerce, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the duck typed object to coerce.
|
||||||
|
*
|
||||||
|
* @param object
|
||||||
|
* the object to coerce
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static DuckType coerce(Object object) {
|
||||||
|
return new DuckType(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coerce the Duck Typed object to the given interface providing it
|
||||||
|
* implements all the necessary methods.
|
||||||
|
*
|
||||||
|
* @param
|
||||||
|
* @param iface
|
||||||
|
* @return an instance of the given interface that wraps the duck typed
|
||||||
|
* class
|
||||||
|
* @throws ClassCastException
|
||||||
|
* if the object being coerced does not implement all the
|
||||||
|
* methods in the given interface.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
public <T> T to(Class iface) {
|
||||||
|
assert iface.isInterface() : "cannot coerce object to a class, must be an interface";
|
||||||
|
if (isA(iface)) {
|
||||||
|
return (T) iface.cast(objectToCoerce);
|
||||||
|
}
|
||||||
|
if (quacksLikeA(iface)) {
|
||||||
|
return generateProxy(iface);
|
||||||
|
}
|
||||||
|
throw new ClassCastException("Could not coerce object of type " + objectToCoerce.getClass() + " to " + iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
private boolean isA(Class iface) {
|
||||||
|
return objectToCoerce.getClass().isInstance(iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the duck typed object can be used with the given
|
||||||
|
* interface.
|
||||||
|
*
|
||||||
|
* @param Type
|
||||||
|
* of the interface to check.
|
||||||
|
* @param iface
|
||||||
|
* Interface class to check
|
||||||
|
* @return true if the object will support all the methods in the interface,
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public boolean quacksLikeA(Class iface) {
|
||||||
|
for (Method method : iface.getMethods()) {
|
||||||
|
if (findMethodBySignature(method) == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
|
private <T> T generateProxy(Class iface) {
|
||||||
|
return (T) Proxy.newProxyInstance(iface.getClassLoader(), new Class[] { iface }, new CoercedProxy());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Method findMethodBySignature(Method method) {
|
||||||
|
try {
|
||||||
|
return objectToCoerce.getClass().getMethod(method.getName(), method.getParameterTypes());
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package de.danoeh.antennapod.util.playback;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import android.view.SurfaceHolder;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
|
@ -342,6 +342,9 @@ public abstract class PlaybackController {
|
||||||
case PlaybackService.NOTIFICATION_TYPE_PLAYBACK_END:
|
case PlaybackService.NOTIFICATION_TYPE_PLAYBACK_END:
|
||||||
onPlaybackEnd();
|
onPlaybackEnd();
|
||||||
break;
|
break;
|
||||||
|
case PlaybackService.NOTIFICATION_TYPE_PLAYBACK_SPEED_CHANGE:
|
||||||
|
onPlaybackSpeedChange();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -369,6 +372,8 @@ public abstract class PlaybackController {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public abstract void onPlaybackSpeedChange();
|
||||||
|
|
||||||
public abstract void onShutdownNotification();
|
public abstract void onShutdownNotification();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -663,6 +668,24 @@ public abstract class PlaybackController {
|
||||||
return status;
|
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() {
|
public boolean isPlayingVideo() {
|
||||||
if (playbackService != null) {
|
if (playbackService != null) {
|
||||||
return PlaybackService.isPlayingVideo();
|
return PlaybackService.isPlayingVideo();
|
||||||
|
@ -670,6 +693,7 @@ public abstract class PlaybackController {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if PlaybackController can communicate with the playback
|
* Returns true if PlaybackController can communicate with the playback
|
||||||
* service.
|
* service.
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue