Merge branch 'develop' into prevent-thrashing
This commit is contained in:
commit
11c3a45f6e
36
.circleci/config.yml
Normal file
36
.circleci/config.yml
Normal file
@ -0,0 +1,36 @@
|
||||
version: 2
|
||||
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/android:api-26-alpha
|
||||
|
||||
working_directory: ~/AntennaPod
|
||||
|
||||
environment:
|
||||
GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx1536m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError"'
|
||||
_JAVA_OPTIONS: "-Xms256m -Xmx1280m"
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-android-{{ checksum "build.gradle" }}
|
||||
# fallback to using the latest cache if no exact match is found
|
||||
- v1-android-
|
||||
|
||||
- run:
|
||||
command: ./gradlew assembleDebug :core:testPlayDebugUnitTest -PdisablePreDex
|
||||
no_output_timeout: 1800
|
||||
|
||||
- store_artifacts:
|
||||
path: app/build/outputs/apk
|
||||
destination: apks
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.android
|
||||
- ~/.gradle
|
||||
- ~/android
|
||||
key: v1-android-{{ checksum "build.gradle" }}
|
@ -83,7 +83,14 @@ android {
|
||||
applicationIdSuffix ".debug"
|
||||
resValue "string", "provider_authority", "de.danoeh.antennapod.debug.provider"
|
||||
buildConfigField STRING, FLATTR_APP_KEY, mFlattrAppKey
|
||||
buildConfigField STRING, FLATTR_APP_SECRET, mFlattrAppSecret
|
||||
buildConfigField STRING, FLATTR_APP_SECRET, mFlattrAppSecret
|
||||
dexcount {
|
||||
if (project.hasProperty("enableDexcountInDebug")) {
|
||||
runOnEachPackage enableDexcountInDebug.toBoolean()
|
||||
} else { // default to not running dexcount
|
||||
runOnEachPackage false
|
||||
}
|
||||
}
|
||||
}
|
||||
release {
|
||||
resValue "string", "provider_authority", "de.danoeh.antennapod.provider"
|
||||
@ -139,6 +146,7 @@ dependencies {
|
||||
implementation "com.android.support:support-v4:$supportVersion"
|
||||
implementation "com.android.support:appcompat-v7:$supportVersion"
|
||||
implementation "com.android.support:design:$supportVersion"
|
||||
implementation "com.android.support:preference-v14:$supportVersion"
|
||||
implementation "com.android.support:gridlayout-v7:$supportVersion"
|
||||
implementation "com.android.support:percent:$supportVersion"
|
||||
implementation "com.android.support:recyclerview-v7:$supportVersion"
|
||||
@ -172,6 +180,7 @@ dependencies {
|
||||
implementation "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion"
|
||||
|
||||
implementation 'com.github.mfietz:fyydlin:v0.3'
|
||||
implementation 'com.github.ByteHamster:SearchPreference:v1.0.8'
|
||||
|
||||
androidTestImplementation "com.jayway.android.robotium:robotium-solo:$robotiumSoloVersion"
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.Chapter;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.syndication.handler.FeedHandler;
|
||||
@ -82,15 +81,7 @@ public class FeedHandlerTest extends InstrumentationTestCase {
|
||||
assertEquals(feed.getLink(), parsedFeed.getLink());
|
||||
assertEquals(feed.getDescription(), parsedFeed.getDescription());
|
||||
assertEquals(feed.getPaymentLink(), parsedFeed.getPaymentLink());
|
||||
|
||||
if (feed.getImage() != null) {
|
||||
FeedImage image = feed.getImage();
|
||||
FeedImage parsedImage = parsedFeed.getImage();
|
||||
assertNotNull(parsedImage);
|
||||
|
||||
assertEquals(image.getTitle(), parsedImage.getTitle());
|
||||
assertEquals(image.getDownload_url(), parsedImage.getDownload_url());
|
||||
}
|
||||
assertEquals(feed.getImageUrl(), parsedFeed.getImageUrl());
|
||||
|
||||
if (feed.getItems() != null) {
|
||||
assertNotNull(parsedFeed.getItems());
|
||||
@ -119,14 +110,7 @@ public class FeedHandlerTest extends InstrumentationTestCase {
|
||||
assertEquals(media.getMime_type(), parsedMedia.getMime_type());
|
||||
}
|
||||
|
||||
if (item.hasItemImage()) {
|
||||
assertTrue(parsedItem.hasItemImage());
|
||||
FeedImage image = item.getImage();
|
||||
FeedImage parsedImage = parsedItem.getImage();
|
||||
|
||||
assertEquals(image.getTitle(), parsedImage.getTitle());
|
||||
assertEquals(image.getDownload_url(), parsedImage.getDownload_url());
|
||||
}
|
||||
assertEquals(item.getImageUrl(), parsedFeed.getImageUrl());
|
||||
|
||||
if (item.getChapters() != null) {
|
||||
assertNotNull(parsedItem.getChapters());
|
||||
@ -158,12 +142,8 @@ public class FeedHandlerTest extends InstrumentationTestCase {
|
||||
}
|
||||
|
||||
private Feed createTestFeed(int numItems, boolean withImage, boolean withFeedMedia, boolean withChapters) {
|
||||
FeedImage image = null;
|
||||
if (withImage) {
|
||||
image = new FeedImage(0, "image", null, "http://example.com/picture", false);
|
||||
}
|
||||
Feed feed = new Feed(0, null, "title", "http://example.com", "This is the description",
|
||||
"http://example.com/payment", "Daniel", "en", null, "http://example.com/feed", image, file.getAbsolutePath(),
|
||||
"http://example.com/payment", "Daniel", "en", null, "http://example.com/feed", "http://example.com/picture", file.getAbsolutePath(),
|
||||
"http://example.com/feed", true);
|
||||
feed.setItems(new ArrayList<>());
|
||||
|
||||
|
@ -15,9 +15,7 @@ import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.Chapter;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.feed.SimpleChapter;
|
||||
@ -124,89 +122,13 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
assertNull(media.getFile_url());
|
||||
}
|
||||
|
||||
public void testDeleteFeed() throws IOException, ExecutionException, InterruptedException, TimeoutException {
|
||||
public void testDeleteFeed() throws ExecutionException, InterruptedException, IOException, TimeoutException {
|
||||
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
|
||||
assertNotNull(destFolder);
|
||||
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(new ArrayList<>());
|
||||
|
||||
// create Feed image
|
||||
File imgFile = new File(destFolder, "image");
|
||||
assertTrue(imgFile.createNewFile());
|
||||
FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
|
||||
image.setOwner(feed);
|
||||
feed.setImage(image);
|
||||
|
||||
List<File> itemFiles = new ArrayList<>();
|
||||
// create items with downloaded media files
|
||||
for (int i = 0; i < 10; i++) {
|
||||
FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed, true);
|
||||
feed.getItems().add(item);
|
||||
|
||||
File enc = new File(destFolder, "file " + i);
|
||||
assertTrue(enc.createNewFile());
|
||||
itemFiles.add(enc);
|
||||
|
||||
FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null, 0, 0);
|
||||
item.setMedia(media);
|
||||
|
||||
item.setChapters(new ArrayList<>());
|
||||
item.getChapters().add(new SimpleChapter(0, "item " + i, item, "example.com"));
|
||||
}
|
||||
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setCompleteFeed(feed);
|
||||
adapter.close();
|
||||
|
||||
assertTrue(feed.getId() != 0);
|
||||
assertTrue(feed.getImage().getId() != 0);
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
assertTrue(item.getId() != 0);
|
||||
assertTrue(item.getMedia().getId() != 0);
|
||||
assertTrue(item.getChapters().get(0).getId() != 0);
|
||||
}
|
||||
|
||||
DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
// check if files still exist
|
||||
assertFalse(imgFile.exists());
|
||||
for (File f : itemFiles) {
|
||||
assertFalse(f.exists());
|
||||
}
|
||||
|
||||
adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
Cursor c = adapter.getFeedCursor(feed.getId());
|
||||
assertEquals(0, c.getCount());
|
||||
c.close();
|
||||
c = adapter.getImageCursor(String.valueOf(image.getId()));
|
||||
assertEquals(0, c.getCount());
|
||||
c.close();
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
|
||||
assertEquals(0, c.getCount());
|
||||
c.close();
|
||||
c = adapter.getSingleFeedMediaCursor(item.getMedia().getId());
|
||||
assertEquals(0, c.getCount());
|
||||
c.close();
|
||||
c = adapter.getSimpleChaptersOfFeedItemCursor(item);
|
||||
assertEquals(0, c.getCount());
|
||||
c.close();
|
||||
}
|
||||
adapter.close();
|
||||
}
|
||||
|
||||
public void testDeleteFeedNoImage() throws ExecutionException, InterruptedException, IOException, TimeoutException {
|
||||
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
|
||||
assertNotNull(destFolder);
|
||||
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(new ArrayList<>());
|
||||
|
||||
feed.setImage(null);
|
||||
|
||||
List<File> itemFiles = new ArrayList<>();
|
||||
// create items with downloaded media files
|
||||
for (int i = 0; i < 10; i++) {
|
||||
@ -261,13 +183,7 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(null);
|
||||
|
||||
// create Feed image
|
||||
File imgFile = new File(destFolder, "image");
|
||||
assertTrue(imgFile.createNewFile());
|
||||
FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
|
||||
image.setOwner(feed);
|
||||
feed.setImage(image);
|
||||
feed.setImageUrl("url");
|
||||
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
@ -275,21 +191,14 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
adapter.close();
|
||||
|
||||
assertTrue(feed.getId() != 0);
|
||||
assertTrue(feed.getImage().getId() != 0);
|
||||
|
||||
DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
// check if files still exist
|
||||
assertFalse(imgFile.exists());
|
||||
|
||||
adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
Cursor c = adapter.getFeedCursor(feed.getId());
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
c = adapter.getImageCursor(String.valueOf(image.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
adapter.close();
|
||||
}
|
||||
|
||||
@ -300,12 +209,7 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(new ArrayList<>());
|
||||
|
||||
// create Feed image
|
||||
File imgFile = new File(destFolder, "image");
|
||||
assertTrue(imgFile.createNewFile());
|
||||
FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
|
||||
image.setOwner(feed);
|
||||
feed.setImage(image);
|
||||
feed.setImageUrl("url");
|
||||
|
||||
// create items
|
||||
for (int i = 0; i < 10; i++) {
|
||||
@ -320,24 +224,18 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
adapter.close();
|
||||
|
||||
assertTrue(feed.getId() != 0);
|
||||
assertTrue(feed.getImage().getId() != 0);
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
assertTrue(item.getId() != 0);
|
||||
}
|
||||
|
||||
DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
// check if files still exist
|
||||
assertFalse(imgFile.exists());
|
||||
|
||||
adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
Cursor c = adapter.getFeedCursor(feed.getId());
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
c = adapter.getImageCursor(String.valueOf(image.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
@ -346,65 +244,6 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
adapter.close();
|
||||
}
|
||||
|
||||
public void testDeleteFeedWithItemImages() throws InterruptedException, ExecutionException, TimeoutException, IOException {
|
||||
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
|
||||
assertNotNull(destFolder);
|
||||
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(new ArrayList<>());
|
||||
|
||||
// create Feed image
|
||||
File imgFile = new File(destFolder, "image");
|
||||
assertTrue(imgFile.createNewFile());
|
||||
FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
|
||||
image.setOwner(feed);
|
||||
feed.setImage(image);
|
||||
|
||||
// create items with images
|
||||
for (int i = 0; i < 10; i++) {
|
||||
FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed);
|
||||
feed.getItems().add(item);
|
||||
File itemImageFile = new File(destFolder, "item-image-" + i);
|
||||
FeedImage itemImage = new FeedImage(0, "item-image" + i, itemImageFile.getAbsolutePath(), "url", true);
|
||||
item.setImage(itemImage);
|
||||
}
|
||||
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setCompleteFeed(feed);
|
||||
adapter.close();
|
||||
|
||||
assertTrue(feed.getId() != 0);
|
||||
assertTrue(feed.getImage().getId() != 0);
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
assertTrue(item.getId() != 0);
|
||||
assertTrue(item.getImage().getId() != 0);
|
||||
}
|
||||
|
||||
DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
// check if files still exist
|
||||
assertFalse(imgFile.exists());
|
||||
|
||||
adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
Cursor c = adapter.getFeedCursor(feed.getId());
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
c = adapter.getImageCursor(String.valueOf(image.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
c = adapter.getImageCursor(String.valueOf(item.getImage().getId()));
|
||||
assertEquals(0, c.getCount());
|
||||
c.close();
|
||||
}
|
||||
adapter.close();
|
||||
}
|
||||
|
||||
public void testDeleteFeedWithQueueItems() throws ExecutionException, InterruptedException, TimeoutException {
|
||||
File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
|
||||
assertNotNull(destFolder);
|
||||
@ -412,11 +251,7 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(new ArrayList<>());
|
||||
|
||||
// create Feed image
|
||||
File imgFile = new File(destFolder, "image");
|
||||
FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
|
||||
image.setOwner(feed);
|
||||
feed.setImage(image);
|
||||
feed.setImageUrl("url");
|
||||
|
||||
List<File> itemFiles = new ArrayList<>();
|
||||
// create items with downloaded media files
|
||||
@ -437,7 +272,6 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
adapter.close();
|
||||
|
||||
assertTrue(feed.getId() != 0);
|
||||
assertTrue(feed.getImage().getId() != 0);
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
assertTrue(item.getId() != 0);
|
||||
assertTrue(item.getMedia().getId() != 0);
|
||||
@ -460,9 +294,6 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
Cursor c = adapter.getFeedCursor(feed.getId());
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
c = adapter.getImageCursor(String.valueOf(image.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
@ -484,11 +315,7 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
Feed feed = new Feed("url", null, "title");
|
||||
feed.setItems(new ArrayList<>());
|
||||
|
||||
// create Feed image
|
||||
File imgFile = new File(destFolder, "image");
|
||||
FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true);
|
||||
image.setOwner(feed);
|
||||
feed.setImage(image);
|
||||
feed.setImageUrl("url");
|
||||
|
||||
List<File> itemFiles = new ArrayList<>();
|
||||
// create items with downloaded media files
|
||||
@ -509,7 +336,6 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
adapter.close();
|
||||
|
||||
assertTrue(feed.getId() != 0);
|
||||
assertTrue(feed.getImage().getId() != 0);
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
assertTrue(item.getId() != 0);
|
||||
assertTrue(item.getMedia().getId() != 0);
|
||||
@ -522,9 +348,6 @@ public class DBWriterTest extends InstrumentationTestCase {
|
||||
Cursor c = adapter.getFeedCursor(feed.getId());
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
c = adapter.getImageCursor(String.valueOf(image.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
c.close();
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
|
||||
assertTrue(c.getCount() == 0);
|
||||
|
@ -55,6 +55,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
} else {
|
||||
otherTheme = R.string.pref_theme_title_light;
|
||||
}
|
||||
solo.clickOnText(solo.getString(R.string.user_interface_label));
|
||||
solo.clickOnText(solo.getString(R.string.pref_set_theme_title));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(solo.getString(otherTheme));
|
||||
@ -69,6 +70,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
} else {
|
||||
otherTheme = R.string.pref_theme_title_light;
|
||||
}
|
||||
solo.clickOnText(solo.getString(R.string.user_interface_label));
|
||||
solo.clickOnText(solo.getString(R.string.pref_set_theme_title));
|
||||
solo.waitForDialogToOpen(1000);
|
||||
solo.clickOnText(solo.getString(otherTheme));
|
||||
@ -76,6 +78,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testExpandNotification() {
|
||||
solo.clickOnText(solo.getString(R.string.user_interface_label));
|
||||
final int priority = UserPreferences.getNotifyPriority();
|
||||
solo.clickOnText(solo.getString(R.string.pref_expandNotify_title));
|
||||
assertTrue(solo.waitForCondition(() -> priority != UserPreferences.getNotifyPriority(), Timeout.getLargeTimeout()));
|
||||
@ -84,7 +87,10 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testEnablePersistentPlaybackControls() {
|
||||
solo.clickOnText(solo.getString(R.string.user_interface_label));
|
||||
final boolean persistNotify = UserPreferences.isPersistNotify();
|
||||
solo.scrollDown();
|
||||
solo.scrollDown();
|
||||
solo.clickOnText(solo.getString(R.string.pref_persistNotify_title));
|
||||
assertTrue(solo.waitForCondition(() -> persistNotify != UserPreferences.isPersistNotify(), Timeout.getLargeTimeout()));
|
||||
solo.clickOnText(solo.getString(R.string.pref_persistNotify_title));
|
||||
@ -92,6 +98,8 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testSetLockscreenButtons() {
|
||||
solo.clickOnText(solo.getString(R.string.user_interface_label));
|
||||
solo.scrollDown();
|
||||
String[] buttons = res.getStringArray(R.array.compact_notification_buttons_options);
|
||||
solo.clickOnText(solo.getString(R.string.pref_compact_notification_buttons_title));
|
||||
solo.waitForDialogToOpen(1000);
|
||||
@ -116,7 +124,10 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testEnqueueAtFront() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
final boolean enqueueAtFront = UserPreferences.enqueueAtFront();
|
||||
solo.scrollDown();
|
||||
solo.scrollDown();
|
||||
solo.clickOnText(solo.getString(R.string.pref_queueAddToFront_title));
|
||||
assertTrue(solo.waitForCondition(() -> enqueueAtFront != UserPreferences.enqueueAtFront(), Timeout.getLargeTimeout()));
|
||||
solo.clickOnText(solo.getString(R.string.pref_queueAddToFront_title));
|
||||
@ -124,6 +135,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testHeadPhonesDisconnect() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
final boolean pauseOnHeadsetDisconnect = UserPreferences.isPauseOnHeadsetDisconnect();
|
||||
solo.clickOnText(solo.getString(R.string.pref_pauseOnHeadsetDisconnect_title));
|
||||
assertTrue(solo.waitForCondition(() -> pauseOnHeadsetDisconnect != UserPreferences.isPauseOnHeadsetDisconnect(), Timeout.getLargeTimeout()));
|
||||
@ -132,6 +144,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testHeadPhonesReconnect() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
if(UserPreferences.isPauseOnHeadsetDisconnect() == false) {
|
||||
solo.clickOnText(solo.getString(R.string.pref_pauseOnHeadsetDisconnect_title));
|
||||
assertTrue(solo.waitForCondition(UserPreferences::isPauseOnHeadsetDisconnect, Timeout.getLargeTimeout()));
|
||||
@ -144,6 +157,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testBluetoothReconnect() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
if(UserPreferences.isPauseOnHeadsetDisconnect() == false) {
|
||||
solo.clickOnText(solo.getString(R.string.pref_pauseOnHeadsetDisconnect_title));
|
||||
assertTrue(solo.waitForCondition(UserPreferences::isPauseOnHeadsetDisconnect, Timeout.getLargeTimeout()));
|
||||
@ -156,7 +170,10 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testContinuousPlayback() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
final boolean continuousPlayback = UserPreferences.isFollowQueue();
|
||||
solo.scrollDown();
|
||||
solo.scrollDown();
|
||||
solo.clickOnText(solo.getString(R.string.pref_followQueue_title));
|
||||
assertTrue(solo.waitForCondition(() -> continuousPlayback != UserPreferences.isFollowQueue(), Timeout.getLargeTimeout()));
|
||||
solo.clickOnText(solo.getString(R.string.pref_followQueue_title));
|
||||
@ -164,6 +181,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testAutoDelete() {
|
||||
solo.clickOnText(solo.getString(R.string.storage_pref));
|
||||
final boolean autoDelete = UserPreferences.isAutoDelete();
|
||||
solo.clickOnText(solo.getString(R.string.pref_auto_delete_title));
|
||||
assertTrue(solo.waitForCondition(() -> autoDelete != UserPreferences.isAutoDelete(), Timeout.getLargeTimeout()));
|
||||
@ -172,6 +190,9 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testPlaybackSpeeds() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
solo.scrollDown();
|
||||
solo.scrollDown();
|
||||
solo.clickOnText(solo.getString(R.string.pref_playback_speed_title));
|
||||
solo.waitForDialogToOpen(1000);
|
||||
assertTrue(solo.searchText(res.getStringArray(R.array.playback_speed_values)[0]));
|
||||
@ -180,6 +201,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testPauseForInterruptions() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
final boolean pauseForFocusLoss = UserPreferences.shouldPauseForFocusLoss();
|
||||
solo.clickOnText(solo.getString(R.string.pref_pausePlaybackForFocusLoss_title));
|
||||
assertTrue(solo.waitForCondition(() -> pauseForFocusLoss != UserPreferences.shouldPauseForFocusLoss(), Timeout.getLargeTimeout()));
|
||||
@ -188,6 +210,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testDisableUpdateInterval() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervallOrTime_sum));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervallOrTime_Disable));
|
||||
@ -195,6 +218,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testSetUpdateInterval() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervallOrTime_title));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervallOrTime_Interval));
|
||||
@ -207,6 +231,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testMobileUpdates() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
final boolean mobileUpdates = UserPreferences.isAllowMobileUpdate();
|
||||
solo.clickOnText(solo.getString(R.string.pref_mobileUpdate_title));
|
||||
assertTrue(solo.waitForCondition(() -> mobileUpdates != UserPreferences.isAllowMobileUpdate(), Timeout.getLargeTimeout()));
|
||||
@ -215,6 +240,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testSetSequentialDownload() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_parallel_downloads_title));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clearEditText(0);
|
||||
@ -224,6 +250,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testSetParallelDownloads() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_parallel_downloads_title));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clearEditText(0);
|
||||
@ -233,6 +260,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testSetParallelDownloadsInvalidInput() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_parallel_downloads_title));
|
||||
solo.waitForDialogToOpen();
|
||||
solo.clearEditText(0);
|
||||
@ -248,6 +276,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
String[] values = res.getStringArray(R.array.episode_cache_size_values);
|
||||
String entry = entries[entries.length/2];
|
||||
final int value = Integer.valueOf(values[values.length/2]);
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.waitForText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.clickOnText(solo.getString(R.string.pref_episode_cache_title));
|
||||
@ -261,6 +290,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
String[] values = res.getStringArray(R.array.episode_cache_size_values);
|
||||
String minEntry = entries[0];
|
||||
final int minValue = Integer.valueOf(values[0]);
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.waitForText(solo.getString(R.string.pref_automatic_download_title));
|
||||
if(!UserPreferences.isEnableAutodownload()) {
|
||||
@ -278,6 +308,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
String[] values = res.getStringArray(R.array.episode_cache_size_values);
|
||||
String maxEntry = entries[entries.length-1];
|
||||
final int maxValue = Integer.valueOf(values[values.length-1]);
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.waitForText(solo.getString(R.string.pref_automatic_download_title));
|
||||
if(!UserPreferences.isEnableAutodownload()) {
|
||||
@ -291,6 +322,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
|
||||
public void testAutomaticDownload() {
|
||||
final boolean automaticDownload = UserPreferences.isEnableAutodownload();
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.waitForText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
@ -312,6 +344,8 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testEpisodeCleanupQueueOnly() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.clickOnText(solo.getString(R.string.pref_episode_cleanup_title));
|
||||
solo.waitForText(solo.getString(R.string.episode_cleanup_queue_removal));
|
||||
solo.clickOnText(solo.getString(R.string.episode_cleanup_queue_removal));
|
||||
@ -323,6 +357,8 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testEpisodeCleanupNeverAlg() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.clickOnText(solo.getString(R.string.pref_episode_cleanup_title));
|
||||
solo.waitForText(solo.getString(R.string.episode_cleanup_never));
|
||||
solo.clickOnText(solo.getString(R.string.episode_cleanup_never));
|
||||
@ -334,6 +370,8 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testEpisodeCleanupClassic() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.clickOnText(solo.getString(R.string.pref_episode_cleanup_title));
|
||||
solo.waitForText(solo.getString(R.string.episode_cleanup_after_listening));
|
||||
solo.clickOnText(solo.getString(R.string.episode_cleanup_after_listening));
|
||||
@ -349,6 +387,8 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testEpisodeCleanupNumDays() {
|
||||
solo.clickOnText(solo.getString(R.string.network_pref));
|
||||
solo.clickOnText(solo.getString(R.string.pref_automatic_download_title));
|
||||
solo.clickOnText(solo.getString(R.string.pref_episode_cleanup_title));
|
||||
solo.waitForText(solo.getString(R.string.episode_cleanup_after_listening));
|
||||
solo.clickOnText("5");
|
||||
@ -368,6 +408,9 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
int seconds = UserPreferences.getRewindSecs();
|
||||
int deltas[] = res.getIntArray(R.array.seek_delta_values);
|
||||
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
solo.scrollDown();
|
||||
solo.scrollDown();
|
||||
solo.clickOnText(solo.getString(R.string.pref_rewind));
|
||||
solo.waitForDialogToOpen();
|
||||
|
||||
@ -386,6 +429,9 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
|
||||
}
|
||||
|
||||
public void testFastForwardChange() {
|
||||
solo.clickOnText(solo.getString(R.string.playback_pref));
|
||||
solo.scrollDown();
|
||||
solo.scrollDown();
|
||||
for (int i = 2; i > 0; i--) { // repeat twice to catch any error where fastforward is tracking rewind
|
||||
int seconds = UserPreferences.getFastForwardSecs();
|
||||
int deltas[] = res.getIntArray(R.array.seek_delta_values);
|
||||
|
@ -22,7 +22,6 @@ import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.event.QueueEvent;
|
||||
import de.danoeh.antennapod.core.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
@ -136,12 +135,9 @@ class UITestUtils {
|
||||
public void addHostedFeedData() throws IOException {
|
||||
if (feedDataHosted) throw new IllegalStateException("addHostedFeedData was called twice on the same instance");
|
||||
for (int i = 0; i < NUM_FEEDS; i++) {
|
||||
File bitmapFile = newBitmapFile("image" + i);
|
||||
FeedImage image = new FeedImage(0, "image " + i, null, hostFile(bitmapFile), false);
|
||||
Feed feed = new Feed(0, null, "Title " + i, "http://example.com/" + i, "Description of feed " + i,
|
||||
"http://example.com/pay/feed" + i, "author " + i, "en", Feed.TYPE_RSS2, "feed" + i, image, null,
|
||||
"http://example.com/pay/feed" + i, "author " + i, "en", Feed.TYPE_RSS2, "feed" + i, null, null,
|
||||
"http://example.com/feed/src/" + i, false);
|
||||
image.setOwner(feed);
|
||||
|
||||
// create items
|
||||
List<FeedItem> items = new ArrayList<>();
|
||||
@ -187,12 +183,6 @@ class UITestUtils {
|
||||
List<FeedItem> queue = new ArrayList<>();
|
||||
for (Feed feed : hostedFeeds) {
|
||||
feed.setDownloaded(true);
|
||||
if (feed.getImage() != null) {
|
||||
FeedImage image = feed.getImage();
|
||||
int fileId = Integer.parseInt(StringUtils.substringAfter(image.getDownload_url(), "files/"));
|
||||
image.setFile_url(server.accessFile(fileId).getAbsolutePath());
|
||||
image.setDownloaded(true);
|
||||
}
|
||||
if (downloadEpisodes) {
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
if (item.hasMedia()) {
|
||||
|
@ -38,9 +38,6 @@ public class UITestUtilsTest extends InstrumentationTestCase {
|
||||
|
||||
for (Feed feed : feeds) {
|
||||
testUrlReachable(feed.getDownload_url());
|
||||
if (feed.getImage() != null) {
|
||||
testUrlReachable(feed.getImage().getDownload_url());
|
||||
}
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
if (item.hasMedia()) {
|
||||
testUrlReachable(item.getMedia().getDownload_url());
|
||||
@ -66,9 +63,6 @@ public class UITestUtilsTest extends InstrumentationTestCase {
|
||||
|
||||
for (Feed feed : uiTestUtils.hostedFeeds) {
|
||||
assertTrue(feed.getId() != 0);
|
||||
if (feed.getImage() != null) {
|
||||
assertTrue(feed.getImage().getId() != 0);
|
||||
}
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
assertTrue(item.getId() != 0);
|
||||
if (item.hasMedia()) {
|
||||
|
@ -2,7 +2,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="de.danoeh.antennapod"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="1060595"
|
||||
android:versionCode="1060596"
|
||||
android:versionName="1.6.5">
|
||||
<!--
|
||||
Version code schema:
|
||||
@ -118,12 +118,13 @@
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".service.PlayerWidgetService"
|
||||
android:name=".core.service.PlayerWidgetJobService"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE"
|
||||
android:enabled="true"
|
||||
android:exported="false">
|
||||
</service>
|
||||
|
||||
<receiver android:name=".receiver.PlayerWidget">
|
||||
<receiver android:name=".core.receiver.PlayerWidget">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
|
||||
</intent-filter>
|
||||
|
@ -21,8 +21,7 @@ import java.nio.charset.Charset;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import rx.Observable;
|
||||
import rx.Subscriber;
|
||||
import rx.Single;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
@ -34,10 +33,8 @@ public class AboutActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = AboutActivity.class.getSimpleName();
|
||||
|
||||
private WebView webview;
|
||||
private LinearLayout webviewContainer;
|
||||
private int depth = 0;
|
||||
|
||||
private WebView webView;
|
||||
private LinearLayout webViewContainer;
|
||||
private Subscription subscription;
|
||||
|
||||
@Override
|
||||
@ -46,28 +43,25 @@ public class AboutActivity extends AppCompatActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
||||
setContentView(R.layout.about);
|
||||
webviewContainer = (LinearLayout) findViewById(R.id.webvContainer);
|
||||
webview = (WebView) findViewById(R.id.webvAbout);
|
||||
webview.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
|
||||
webViewContainer = (LinearLayout) findViewById(R.id.webViewContainer);
|
||||
webView = (WebView) findViewById(R.id.webViewAbout);
|
||||
webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
|
||||
if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
|
||||
if (Build.VERSION.SDK_INT >= 11
|
||||
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
|
||||
webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
|
||||
webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||
}
|
||||
webview.setBackgroundColor(Color.TRANSPARENT);
|
||||
webView.setBackgroundColor(Color.TRANSPARENT);
|
||||
}
|
||||
webview.setWebViewClient(new WebViewClient() {
|
||||
webView.setWebViewClient(new WebViewClient() {
|
||||
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
if(url.startsWith("http")) {
|
||||
depth++;
|
||||
return false;
|
||||
} else {
|
||||
if (!url.startsWith("http")) {
|
||||
url = url.replace("file:///android_asset/", "");
|
||||
loadAsset(url);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
@ -75,7 +69,7 @@ public class AboutActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void loadAsset(String filename) {
|
||||
subscription = Observable.create((Observable.OnSubscribe<String>) subscriber -> {
|
||||
subscription = Single.create(subscriber -> {
|
||||
InputStream input = null;
|
||||
try {
|
||||
TypedArray res = AboutActivity.this.getTheme().obtainStyledAttributes(
|
||||
@ -85,8 +79,7 @@ public class AboutActivity extends AppCompatActivity {
|
||||
res.recycle();
|
||||
input = getAssets().open(filename);
|
||||
String webViewData = IOUtils.toString(input, Charset.defaultCharset());
|
||||
if(!webViewData.startsWith("<!DOCTYPE html>")) {
|
||||
//webViewData = webViewData.replace("\n\n", "</p><p>");
|
||||
if (!webViewData.startsWith("<!DOCTYPE html>")) {
|
||||
webViewData = webViewData.replace("%", "%");
|
||||
webViewData =
|
||||
"<!DOCTYPE html>" +
|
||||
@ -106,35 +99,29 @@ public class AboutActivity extends AppCompatActivity {
|
||||
" </style>" +
|
||||
"</head><body><p>" + webViewData + "</p></body></html>";
|
||||
webViewData = webViewData.replace("\n", "<br/>");
|
||||
depth++;
|
||||
} else {
|
||||
depth = 0;
|
||||
}
|
||||
webViewData = String.format(webViewData, colorString);
|
||||
subscriber.onNext(webViewData);
|
||||
subscriber.onSuccess(webViewData);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
subscriber.onError(e);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(input);
|
||||
}
|
||||
subscriber.onCompleted();
|
||||
})
|
||||
.subscribeOn(Schedulers.newThread())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
webviewData ->
|
||||
webview.loadDataWithBaseURL("file:///android_asset/", webviewData, "text/html", "utf-8", "about:blank"),
|
||||
webViewData ->
|
||||
webView.loadDataWithBaseURL("file:///android_asset/", webViewData.toString(), "text/html", "utf-8", "file:///android_asset/" + filename.toString()),
|
||||
error -> Log.e(TAG, Log.getStackTraceString(error))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
Log.d(TAG, "depth: " + depth);
|
||||
if(depth == 1) {
|
||||
loadAsset("about.html");
|
||||
} else if(depth > 1) {
|
||||
webview.goBack();
|
||||
if (webView.canGoBack()) {
|
||||
webView.goBack();
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
}
|
||||
@ -156,9 +143,9 @@ public class AboutActivity extends AppCompatActivity {
|
||||
if(subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
if (webviewContainer != null && webview != null) {
|
||||
webviewContainer.removeAllViews();
|
||||
webview.destroy();
|
||||
if (webViewContainer != null && webView != null) {
|
||||
webViewContainer.removeAllViews();
|
||||
webView.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import de.danoeh.antennapod.core.feed.MediaType;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
|
||||
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
|
||||
|
||||
/**
|
||||
@ -34,14 +35,13 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
|
||||
Log.d(TAG, "Received VIEW intent: " + intent.getData().getPath());
|
||||
ExternalMedia media = new ExternalMedia(intent.getData().getPath(),
|
||||
MediaType.AUDIO);
|
||||
Intent launchIntent = new Intent(this, PlaybackService.class);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED,
|
||||
true);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, false);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY,
|
||||
true);
|
||||
startService(launchIntent);
|
||||
|
||||
new PlaybackServiceStarter(this, media)
|
||||
.startWhenPrepared(true)
|
||||
.shouldStream(false)
|
||||
.prepareImmediately(true)
|
||||
.start();
|
||||
|
||||
} else if (PlaybackService.isCasting()) {
|
||||
Intent intent = PlaybackService.getPlayerActivityIntent(this);
|
||||
if (intent.getComponent() != null &&
|
||||
|
@ -8,7 +8,7 @@ import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.content.IntentCompat;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
@ -39,7 +39,10 @@ public class ImportExportActivity extends AppCompatActivity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayShowHomeEnabled(true);
|
||||
}
|
||||
setContentView(R.layout.import_export_activity);
|
||||
|
||||
findViewById(R.id.button_export).setOnClickListener(view -> backup());
|
||||
@ -125,7 +128,7 @@ public class ImportExportActivity extends AppCompatActivity {
|
||||
d.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
|
||||
Intent intent = new Intent(getApplicationContext(), SplashActivity.class);
|
||||
ComponentName cn = intent.getComponent();
|
||||
Intent mainIntent = IntentCompat.makeRestartActivityTask(cn);
|
||||
Intent mainIntent = Intent.makeRestartActivityTask(cn);
|
||||
startActivity(mainIntent);
|
||||
});
|
||||
d.show();
|
||||
|
@ -30,6 +30,8 @@ import android.widget.ListView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import de.danoeh.antennapod.core.event.ServiceEvent;
|
||||
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
@ -200,6 +202,8 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
|
||||
transaction.commit();
|
||||
|
||||
checkFirstLaunch();
|
||||
NotificationUtils.createChannels(this);
|
||||
UserPreferences.restartUpdateAlarm(false);
|
||||
}
|
||||
|
||||
private void saveLastNavFragment(String tag) {
|
||||
@ -739,6 +743,15 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
|
||||
loadData();
|
||||
}
|
||||
|
||||
public void onEventMainThread(ServiceEvent event) {
|
||||
Log.d(TAG, "onEvent(" + event + ")");
|
||||
switch(event.action) {
|
||||
case SERVICE_STARTED:
|
||||
externalPlayerFragment.connectToPlaybackService();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void onEventMainThread(ProgressEvent event) {
|
||||
Log.d(TAG, "onEvent(" + event + ")");
|
||||
switch(event.action) {
|
||||
|
@ -34,6 +34,7 @@ import com.joanzapata.iconify.fonts.FontAwesomeIcons;
|
||||
import java.util.Locale;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.event.ServiceEvent;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
@ -42,6 +43,7 @@ import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.core.util.Flavors;
|
||||
import de.danoeh.antennapod.core.util.ShareUtils;
|
||||
import de.danoeh.antennapod.core.util.StorageUtils;
|
||||
@ -270,6 +272,9 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
controller.release();
|
||||
}
|
||||
controller = newPlaybackController();
|
||||
setupGUI();
|
||||
loadMediaInfo();
|
||||
onPositionObserverUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -320,11 +325,11 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
((FeedMedia) media).getItem().getFlattrStatus().flattrable()
|
||||
);
|
||||
|
||||
boolean hasWebsiteLink = media != null && media.getWebsiteLink() != null;
|
||||
boolean hasWebsiteLink = ( getWebsiteLinkWithFallback(media) != null );
|
||||
menu.findItem(R.id.visit_website_item).setVisible(hasWebsiteLink);
|
||||
|
||||
boolean isItemAndHasLink = isFeedMedia &&
|
||||
((FeedMedia) media).getItem() != null && ((FeedMedia) media).getItem().getLink() != null;
|
||||
ShareUtils.hasLinkToShare(((FeedMedia) media).getItem());
|
||||
menu.findItem(R.id.share_link_item).setVisible(isItemAndHasLink);
|
||||
menu.findItem(R.id.share_link_with_position_item).setVisible(isItemAndHasLink);
|
||||
|
||||
@ -560,7 +565,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
});
|
||||
break;
|
||||
case R.id.visit_website_item:
|
||||
Uri uri = Uri.parse(media.getWebsiteLink());
|
||||
Uri uri = Uri.parse(getWebsiteLinkWithFallback(media));
|
||||
startActivity(new Intent(Intent.ACTION_VIEW, uri));
|
||||
break;
|
||||
case R.id.support_item:
|
||||
@ -603,16 +608,37 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
}
|
||||
}
|
||||
|
||||
private static String getWebsiteLinkWithFallback(Playable media) {
|
||||
if (media == null) {
|
||||
return null;
|
||||
} else if (media.getWebsiteLink() != null) {
|
||||
return media.getWebsiteLink();
|
||||
} else if (media instanceof FeedMedia) {
|
||||
return FeedItemUtil.getLinkWithFallback(((FeedMedia)media).getItem());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
Log.d(TAG, "onResume()");
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
if(controller != null) {
|
||||
if (controller != null) {
|
||||
controller.init();
|
||||
}
|
||||
}
|
||||
|
||||
public void onEventMainThread(ServiceEvent event) {
|
||||
Log.d(TAG, "onEvent(" + event + ")");
|
||||
if (event.action == ServiceEvent.Action.SERVICE_STARTED) {
|
||||
if (controller != null) {
|
||||
controller.init();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by 'handleStatus()' when the PlaybackService is waiting for
|
||||
* a video surface.
|
||||
@ -853,6 +879,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
if(controller == null) {
|
||||
return;
|
||||
}
|
||||
controller.init();
|
||||
controller.playPause();
|
||||
}
|
||||
|
||||
|
@ -393,9 +393,9 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
||||
|
||||
subscribeButton = (Button) header.findViewById(R.id.butSubscribe);
|
||||
|
||||
if (feed.getImage() != null && StringUtils.isNotBlank(feed.getImage().getDownload_url())) {
|
||||
if (StringUtils.isNotBlank(feed.getImageUrl())) {
|
||||
Glide.with(this)
|
||||
.load(feed.getImage().getDownload_url())
|
||||
.load(feed.getImageUrl())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
|
@ -1,13 +1,12 @@
|
||||
package de.danoeh.antennapod.activity;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.PreferenceScreen;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceFragmentCompat;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.ViewGroup;
|
||||
@ -15,6 +14,9 @@ import android.widget.FrameLayout;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import com.bytehamster.lib.preferencesearch.SearchPreference;
|
||||
import com.bytehamster.lib.preferencesearch.SearchPreferenceResult;
|
||||
import com.bytehamster.lib.preferencesearch.SearchPreferenceResultListener;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.preferences.PreferenceController;
|
||||
@ -23,19 +25,24 @@ import de.danoeh.antennapod.preferences.PreferenceController;
|
||||
* PreferenceActivity for API 11+. In order to change the behavior of the preference UI, see
|
||||
* PreferenceController.
|
||||
*/
|
||||
public class PreferenceActivity extends AppCompatActivity {
|
||||
public class PreferenceActivity extends AppCompatActivity implements SearchPreferenceResultListener {
|
||||
|
||||
public static final String PARAM_RESOURCE = "resource";
|
||||
private static WeakReference<PreferenceActivity> instance;
|
||||
private PreferenceController preferenceController;
|
||||
private final PreferenceController.PreferenceUI preferenceUI = new PreferenceController.PreferenceUI() {
|
||||
private PreferenceFragment fragment;
|
||||
private PreferenceFragmentCompat fragment;
|
||||
|
||||
@Override
|
||||
public void setFragment(PreferenceFragment fragment) {
|
||||
public void setFragment(PreferenceFragmentCompat fragment) {
|
||||
this.fragment = fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreferenceFragmentCompat getFragment() {
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Preference findPreference(CharSequence key) {
|
||||
return fragment.findPreference(key);
|
||||
@ -47,7 +54,7 @@ public class PreferenceActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Activity getActivity() {
|
||||
public AppCompatActivity getActivity() {
|
||||
return PreferenceActivity.this;
|
||||
}
|
||||
};
|
||||
@ -77,12 +84,21 @@ public class PreferenceActivity extends AppCompatActivity {
|
||||
// since the MainFragment depends on the preferenceController already being created
|
||||
preferenceController = new PreferenceController(preferenceUI);
|
||||
|
||||
PreferenceFragment prefFragment = new MainFragment();
|
||||
showPreferenceScreen(R.xml.preferences, false);
|
||||
}
|
||||
|
||||
private void showPreferenceScreen(int screen, boolean addHistory) {
|
||||
PreferenceFragmentCompat prefFragment = new MainFragment();
|
||||
preferenceUI.setFragment(prefFragment);
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(PARAM_RESOURCE, R.xml.preferences);
|
||||
args.putInt(PARAM_RESOURCE, screen);
|
||||
prefFragment.setArguments(args);
|
||||
getFragmentManager().beginTransaction().replace(R.id.content, prefFragment).commit();
|
||||
if (addHistory) {
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.content, prefFragment)
|
||||
.addToBackStack(getString(PreferenceController.getTitleOfPage(screen))).commit();
|
||||
} else {
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.content, prefFragment).commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -101,10 +117,10 @@ public class PreferenceActivity extends AppCompatActivity {
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
if (getFragmentManager().getBackStackEntryCount() == 0) {
|
||||
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
|
||||
finish();
|
||||
} else {
|
||||
getFragmentManager().popBackStack();
|
||||
getSupportFragmentManager().popBackStack();
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
@ -112,13 +128,23 @@ public class PreferenceActivity extends AppCompatActivity {
|
||||
}
|
||||
}
|
||||
|
||||
public static class MainFragment extends PreferenceFragment {
|
||||
@Override
|
||||
public void onSearchResultClicked(SearchPreferenceResult result) {
|
||||
showPreferenceScreen(result.getResourceFile(), true);
|
||||
result.highlight(preferenceUI.getFragment());
|
||||
}
|
||||
|
||||
public static class MainFragment extends PreferenceFragmentCompat {
|
||||
private int screen;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setRetainInstance(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
screen = getArguments().getInt(PARAM_RESOURCE);
|
||||
addPreferencesFromResource(screen);
|
||||
PreferenceActivity activity = instance.get();
|
||||
@ -133,35 +159,16 @@ public class PreferenceActivity extends AppCompatActivity {
|
||||
super.onResume();
|
||||
PreferenceActivity activity = instance.get();
|
||||
if(activity != null && activity.preferenceController != null) {
|
||||
activity.setTitle(getTitle(screen));
|
||||
activity.setTitle(PreferenceController.getTitleOfPage(screen));
|
||||
activity.preferenceUI.setFragment(this);
|
||||
activity.preferenceController.onResume(screen);
|
||||
}
|
||||
}
|
||||
|
||||
private int getTitle(int preferences) {
|
||||
switch (preferences) {
|
||||
case R.xml.preferences_network:
|
||||
return R.string.network_pref;
|
||||
case R.xml.preferences_autodownload:
|
||||
return R.string.pref_automatic_download_title;
|
||||
case R.xml.preferences_playback:
|
||||
return R.string.playback_pref;
|
||||
case R.xml.preferences_storage:
|
||||
return R.string.storage_pref;
|
||||
case R.xml.preferences_user_interface:
|
||||
return R.string.user_interface_label;
|
||||
case R.xml.preferences_integrations:
|
||||
return R.string.integrations_label;
|
||||
default:
|
||||
return R.string.settings_label;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
PreferenceActivity activity = instance.get();
|
||||
if (screen == R.xml.preferences_integrations) {
|
||||
if (screen == R.xml.preferences_gpodder) {
|
||||
activity.preferenceController.unregisterGpodnet();
|
||||
}
|
||||
super.onPause();
|
||||
|
@ -30,6 +30,7 @@ import de.danoeh.antennapod.core.service.playback.PlayerStatus;
|
||||
import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
|
||||
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
|
||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
|
||||
import de.danoeh.antennapod.view.AspectRatioVideoView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
@ -82,14 +83,12 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||
Log.d(TAG, "Received VIEW intent: " + intent.getData().getPath());
|
||||
ExternalMedia media = new ExternalMedia(intent.getData().getPath(),
|
||||
MediaType.VIDEO);
|
||||
Intent launchIntent = new Intent(this, PlaybackService.class);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED,
|
||||
true);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, false);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY,
|
||||
true);
|
||||
startService(launchIntent);
|
||||
|
||||
new PlaybackServiceStarter(this, media)
|
||||
.startWhenPrepared(true)
|
||||
.shouldStream(false)
|
||||
.prepareImmediately(true)
|
||||
.start();
|
||||
} else if (PlaybackService.isCasting()) {
|
||||
Intent intent = PlaybackService.getPlayerActivityIntent(this);
|
||||
if (!intent.getComponent().getClassName().equals(VideoplayerActivity.class.getName())) {
|
||||
|
@ -29,12 +29,12 @@ import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.DateUtils;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import de.danoeh.antennapod.core.util.ThemeUtils;
|
||||
import de.danoeh.antennapod.fragment.ItemFragment;
|
||||
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
||||
|
||||
@ -67,11 +67,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
|
||||
this.actionButtonCallback = actionButtonCallback;
|
||||
this.showOnlyNewEpisodes = showOnlyNewEpisodes;
|
||||
|
||||
if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
|
||||
playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_dark);
|
||||
} else {
|
||||
playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_light);
|
||||
}
|
||||
playingBackGroundColor = ThemeUtils.getColorFromAttr(mainActivity, R.attr.currently_playing_background);
|
||||
normalBackGroundColor = ContextCompat.getColor(mainActivity, android.R.color.transparent);
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,9 @@ import android.widget.TextView;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.feed.Chapter;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.util.ChapterUtils;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.ThemeUtils;
|
||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
|
||||
public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
|
||||
@ -143,9 +143,7 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
|
||||
|
||||
Chapter current = ChapterUtils.getCurrentChapter(media);
|
||||
if (current == sc) {
|
||||
boolean darkTheme = UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark;
|
||||
int highlight = darkTheme ? R.color.highlight_dark : R.color.highlight_light;
|
||||
int playingBackGroundColor = ContextCompat.getColor(getContext(), highlight);
|
||||
int playingBackGroundColor = ThemeUtils.getColorFromAttr(getContext(), R.attr.currently_playing_background);
|
||||
holder.view.setBackgroundColor(playingBackGroundColor);
|
||||
} else {
|
||||
holder.view.setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
|
||||
|
@ -6,6 +6,7 @@ import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
@ -80,13 +81,19 @@ public class DefaultActionButtonCallback implements ActionButtonCallback {
|
||||
Toast.makeText(context, R.string.download_canceled_msg, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
} else { // media is downloaded
|
||||
if (item.hasMedia() && item.getMedia().isCurrentlyPlaying()) {
|
||||
if (media.isCurrentlyPlaying()) {
|
||||
new PlaybackServiceStarter(context, media)
|
||||
.startWhenPrepared(true)
|
||||
.shouldStream(false)
|
||||
.start();
|
||||
context.sendBroadcast(new Intent(PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE));
|
||||
}
|
||||
else if (item.hasMedia() && item.getMedia().isCurrentlyPaused()) {
|
||||
} else if (media.isCurrentlyPaused()) {
|
||||
new PlaybackServiceStarter(context, media)
|
||||
.startWhenPrepared(true)
|
||||
.shouldStream(false)
|
||||
.start();
|
||||
context.sendBroadcast(new Intent(PlaybackService.ACTION_RESUME_PLAY_CURRENT_EPISODE));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
DBTasks.playMedia(context, media, false, true, false);
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ import com.joanzapata.iconify.widget.IconTextView;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.service.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
@ -67,8 +66,6 @@ public class DownloadLogAdapter extends BaseAdapter {
|
||||
holder.type.setText(R.string.download_type_feed);
|
||||
} else if (status.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
|
||||
holder.type.setText(R.string.download_type_media);
|
||||
} else if (status.getFeedfileType() == FeedImage.FEEDFILETYPE_FEEDIMAGE) {
|
||||
holder.type.setText(R.string.download_type_image);
|
||||
}
|
||||
if (status.getTitle() != null) {
|
||||
holder.title.setText(status.getTitle());
|
||||
@ -94,8 +91,7 @@ public class DownloadLogAdapter extends BaseAdapter {
|
||||
}
|
||||
holder.reason.setText(reasonText);
|
||||
holder.reason.setVisibility(View.VISIBLE);
|
||||
if(status.getFeedfileType() != FeedImage.FEEDFILETYPE_FEEDIMAGE &&
|
||||
!newerWasSuccessful(position, status.getFeedfileType(), status.getFeedfileId())) {
|
||||
if(!newerWasSuccessful(position, status.getFeedfileType(), status.getFeedfileId())) {
|
||||
holder.retry.setVisibility(View.VISIBLE);
|
||||
holder.retry.setOnClickListener(clickListener);
|
||||
ButtonHolder btnHolder;
|
||||
|
@ -100,8 +100,10 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter {
|
||||
FeedItem.State state = item.getState();
|
||||
if (state == FeedItem.State.PLAYING) {
|
||||
holder.butSecondary.setEnabled(false);
|
||||
holder.butSecondary.setAlpha(0.5f);
|
||||
} else {
|
||||
holder.butSecondary.setEnabled(true);
|
||||
holder.butSecondary.setAlpha(1.0f);
|
||||
}
|
||||
holder.butSecondary.setFocusable(false);
|
||||
holder.butSecondary.setTag(item);
|
||||
|
@ -21,7 +21,6 @@ import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.feed.MediaType;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.util.DateUtils;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
@ -60,11 +59,7 @@ public class FeedItemlistAdapter extends BaseAdapter {
|
||||
this.actionButtonUtils = new ActionButtonUtils(context);
|
||||
this.makePlayedItemsTransparent = makePlayedItemsTransparent;
|
||||
|
||||
if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
|
||||
playingBackGroundColor = ContextCompat.getColor(context, R.color.highlight_dark);
|
||||
} else {
|
||||
playingBackGroundColor = ContextCompat.getColor(context, R.color.highlight_light);
|
||||
}
|
||||
playingBackGroundColor = ThemeUtils.getColorFromAttr(context, R.attr.currently_playing_background);
|
||||
normalBackGroundColor = ContextCompat.getColor(context, android.R.color.transparent);
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ import android.widget.TextView;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
|
||||
import de.danoeh.antennapod.core.util.ThemeUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
@ -75,11 +76,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
|
||||
this.itemTouchHelper = itemTouchHelper;
|
||||
locked = UserPreferences.isQueueLocked();
|
||||
|
||||
if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
|
||||
playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_dark);
|
||||
} else {
|
||||
playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_light);
|
||||
}
|
||||
playingBackGroundColor = ThemeUtils.getColorFromAttr(mainActivity, R.attr.currently_playing_background);
|
||||
normalBackGroundColor = ContextCompat.getColor(mainActivity, android.R.color.transparent);
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,6 @@ public class ExternalPlayerFragment extends Fragment {
|
||||
private ImageButton butPlay;
|
||||
private TextView mFeedName;
|
||||
private ProgressBar mProgressBar;
|
||||
|
||||
private PlaybackController controller;
|
||||
|
||||
public ExternalPlayerFragment() {
|
||||
@ -83,6 +82,11 @@ public class ExternalPlayerFragment extends Fragment {
|
||||
controller.playPause();
|
||||
}
|
||||
});
|
||||
loadMediaInfo();
|
||||
}
|
||||
|
||||
public void connectToPlaybackService() {
|
||||
controller.init();
|
||||
}
|
||||
|
||||
private PlaybackController setupPlaybackController() {
|
||||
@ -164,36 +168,35 @@ public class ExternalPlayerFragment extends Fragment {
|
||||
|
||||
private boolean loadMediaInfo() {
|
||||
Log.d(TAG, "Loading media info");
|
||||
if (controller != null && controller.serviceAvailable()) {
|
||||
Playable media = controller.getMedia();
|
||||
if (media != null) {
|
||||
txtvTitle.setText(media.getEpisodeTitle());
|
||||
mFeedName.setText(media.getFeedTitle());
|
||||
mProgressBar.setProgress((int)
|
||||
((double) controller.getPosition() / controller.getDuration() * 100));
|
||||
if (controller == null) {
|
||||
Log.w(TAG, "loadMediaInfo was called while PlaybackController was null!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Glide.with(getActivity())
|
||||
.load(media.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.into(imgvCover);
|
||||
Playable media = controller.getMedia();
|
||||
if (media != null) {
|
||||
txtvTitle.setText(media.getEpisodeTitle());
|
||||
mFeedName.setText(media.getFeedTitle());
|
||||
onPositionObserverUpdate();
|
||||
|
||||
fragmentLayout.setVisibility(View.VISIBLE);
|
||||
if (controller.isPlayingVideoLocally()) {
|
||||
butPlay.setVisibility(View.GONE);
|
||||
} else {
|
||||
butPlay.setVisibility(View.VISIBLE);
|
||||
}
|
||||
return true;
|
||||
Glide.with(getActivity())
|
||||
.load(media.getImageLocation())
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.fitCenter()
|
||||
.dontAnimate()
|
||||
.into(imgvCover);
|
||||
|
||||
fragmentLayout.setVisibility(View.VISIBLE);
|
||||
if (controller.isPlayingVideoLocally()) {
|
||||
butPlay.setVisibility(View.GONE);
|
||||
} else {
|
||||
Log.w(TAG, "loadMediaInfo was called while the media object of playbackService was null!");
|
||||
return false;
|
||||
butPlay.setVisibility(View.VISIBLE);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
Log.w(TAG, "loadMediaInfo was called while playbackService was null!");
|
||||
Log.w(TAG, "loadMediaInfo was called while the media object of playbackService was null!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -113,10 +113,13 @@ public class ItemDescriptionFragment extends Fragment implements MediaplayerInfo
|
||||
Log.d(TAG, "Creating view");
|
||||
webvDescription = new WebView(getActivity().getApplicationContext());
|
||||
webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||
|
||||
TypedArray ta = getActivity().getTheme().obtainStyledAttributes(new int[]
|
||||
{android.R.attr.colorBackground});
|
||||
int backgroundColor = ta.getColor(0, UserPreferences.getTheme() ==
|
||||
R.style.Theme_AntennaPod_Dark ? Color.BLACK : Color.WHITE);
|
||||
boolean black = UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark
|
||||
|| UserPreferences.getTheme() == R.style.Theme_AntennaPod_TrueBlack;
|
||||
int backgroundColor = ta.getColor(0, black ? Color.BLACK : Color.WHITE);
|
||||
|
||||
ta.recycle();
|
||||
webvDescription.setBackgroundColor(backgroundColor);
|
||||
if (!NetworkUtils.networkAvailable()) {
|
||||
|
@ -34,6 +34,7 @@ import com.bumptech.glide.Glide;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
import com.joanzapata.iconify.widget.IconButton;
|
||||
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
@ -184,7 +185,8 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
|
||||
txtvTitle.setEllipsize(TextUtils.TruncateAt.END);
|
||||
}
|
||||
webvDescription = (WebView) layout.findViewById(R.id.webvDescription);
|
||||
if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
|
||||
if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark ||
|
||||
UserPreferences.getTheme() == R.style.Theme_AntennaPod_TrueBlack) {
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
|
||||
webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||
}
|
||||
@ -432,6 +434,16 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
|
||||
butAction1Text = R.string.download_label;
|
||||
}
|
||||
}
|
||||
|
||||
FeedItem.State state = item.getState();
|
||||
if (butAction2Text == R.string.delete_label && state == FeedItem.State.PLAYING) {
|
||||
butAction2.setEnabled(false);
|
||||
butAction2.setAlpha(0.5f);
|
||||
} else {
|
||||
butAction2.setEnabled(true);
|
||||
butAction2.setAlpha(1.0f);
|
||||
}
|
||||
|
||||
if(butAction1Icon != null && butAction1Text != 0) {
|
||||
butAction1.setText(butAction1Icon +"\u0020\u0020" + getActivity().getString(butAction1Text));
|
||||
Iconify.addIcons(butAction1);
|
||||
|
@ -534,14 +534,15 @@ public class QueueFragment extends Fragment {
|
||||
private void refreshInfoBar() {
|
||||
String info = queue.size() + getString(R.string.episodes_suffix);
|
||||
if(queue.size() > 0) {
|
||||
long duration = 0;
|
||||
long timeLeft = 0;
|
||||
for(FeedItem item : queue) {
|
||||
if(item.getMedia() != null) {
|
||||
duration += item.getMedia().getDuration();
|
||||
timeLeft += item.getMedia().getDuration() - item.getMedia().getPosition();
|
||||
}
|
||||
}
|
||||
info += " \u2022 ";
|
||||
info += Converter.getDurationStringLocalized(getActivity(), duration);
|
||||
info += getString(R.string.time_left_label);
|
||||
info += Converter.getDurationStringLocalized(getActivity(), timeLeft);
|
||||
}
|
||||
infoBar.setText(info);
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.core.util.ShareUtils;
|
||||
@ -86,7 +87,7 @@ public class FeedItemMenuHandler {
|
||||
mi.setItemVisibility(R.id.add_to_queue_item, false);
|
||||
}
|
||||
|
||||
if (!showExtendedMenu || selectedItem.getLink() == null) {
|
||||
if (!showExtendedMenu || !ShareUtils.hasLinkToShare(selectedItem)) {
|
||||
mi.setItemVisibility(R.id.visit_website_item, false);
|
||||
mi.setItemVisibility(R.id.share_link_item, false);
|
||||
mi.setItemVisibility(R.id.share_link_with_position_item, false);
|
||||
@ -216,7 +217,7 @@ public class FeedItemMenuHandler {
|
||||
DBWriter.setFeedItemAutoDownload(selectedItem, false);
|
||||
break;
|
||||
case R.id.visit_website_item:
|
||||
Uri uri = Uri.parse(selectedItem.getLink());
|
||||
Uri uri = Uri.parse(FeedItemUtil.getLinkWithFallback(selectedItem));
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
if(IntentUtils.isCallable(context, intent)) {
|
||||
context.startActivity(intent);
|
||||
|
@ -20,7 +20,8 @@ public class MenuItemUtils extends de.danoeh.antennapod.core.menuhandler.MenuIte
|
||||
public static void adjustTextColor(Context context, SearchView sv) {
|
||||
if(Build.VERSION.SDK_INT < 14) {
|
||||
EditText searchEditText = (EditText) sv.findViewById(R.id.search_src_text);
|
||||
if(UserPreferences.getTheme() == de.danoeh.antennapod.R.style.Theme_AntennaPod_Dark) {
|
||||
if (UserPreferences.getTheme() == de.danoeh.antennapod.R.style.Theme_AntennaPod_Dark
|
||||
|| UserPreferences.getTheme() == R.style.Theme_AntennaPod_TrueBlack) {
|
||||
searchEditText.setTextColor(Color.WHITE);
|
||||
} else {
|
||||
searchEditText.setTextColor(Color.BLACK);
|
||||
|
@ -4,13 +4,14 @@ import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Build;
|
||||
import android.support.v14.preference.SwitchPreference;
|
||||
import android.support.v7.preference.PreferenceViewHolder;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import de.danoeh.antennapod.R;
|
||||
|
||||
public class MasterSwitchPreference extends SwitchCompatPreference {
|
||||
public class MasterSwitchPreference extends SwitchPreference {
|
||||
|
||||
public MasterSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
@ -29,15 +30,16 @@ public class MasterSwitchPreference extends SwitchCompatPreference {
|
||||
super(context);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onBindView(View view) {
|
||||
super.onBindView(view);
|
||||
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||
super.onBindViewHolder(holder);
|
||||
|
||||
TypedValue typedValue = new TypedValue();
|
||||
getContext().getTheme().resolveAttribute(R.attr.master_switch_background, typedValue, true);
|
||||
view.setBackgroundColor(typedValue.data);
|
||||
holder.itemView.setBackgroundColor(typedValue.data);
|
||||
|
||||
TextView title = (TextView) view.findViewById(android.R.id.title);
|
||||
TextView title = (TextView) holder.findViewById(android.R.id.title);
|
||||
if (title != null) {
|
||||
title.setTypeface(title.getTypeface(), Typeface.BOLD);
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package de.danoeh.antennapod.preferences;
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.app.ProgressDialog;
|
||||
import android.app.TimePickerDialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
@ -18,31 +17,29 @@ import android.net.wifi.WifiConfiguration;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.preference.PreferenceScreen;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.FileProvider;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.Editable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.preference.CheckBoxPreference;
|
||||
import android.support.v7.preference.ListPreference;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceFragmentCompat;
|
||||
import android.support.v7.preference.PreferenceManager;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
import android.text.Html;
|
||||
import android.text.TextWatcher;
|
||||
import android.text.format.DateFormat;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.Log;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
|
||||
import com.bytehamster.lib.preferencesearch.SearchConfiguration;
|
||||
import com.bytehamster.lib.preferencesearch.SearchPreference;
|
||||
import de.danoeh.antennapod.activity.AboutActivity;
|
||||
import com.afollestad.materialdialogs.prefs.MaterialListPreference;
|
||||
import de.danoeh.antennapod.activity.ImportExportActivity;
|
||||
import de.danoeh.antennapod.activity.MediaplayerActivity;
|
||||
import de.danoeh.antennapod.activity.OpmlImportFromPathActivity;
|
||||
@ -99,8 +96,9 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
||||
private static final String PREF_SCREEN_INTEGRATIONS = "prefScreenIntegrations";
|
||||
private static final String PREF_SCREEN_STORAGE = "prefScreenStorage";
|
||||
private static final String PREF_SCREEN_AUTODL = "prefAutoDownloadSettings";
|
||||
private static final String PREF_SCREEN_FLATTR = "prefFlattrSettings";
|
||||
private static final String PREF_SCREEN_GPODDER = "prefGpodderSettings";
|
||||
|
||||
private static final String PREF_FLATTR_SETTINGS = "prefFlattrSettings";
|
||||
private static final String PREF_FLATTR_AUTH = "pref_flattr_authenticate";
|
||||
private static final String PREF_FLATTR_REVOKE = "prefRevokeAccess";
|
||||
private static final String PREF_AUTO_FLATTR_PREFS = "prefAutoFlattrPrefs";
|
||||
@ -181,6 +179,12 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
||||
case R.xml.preferences_integrations:
|
||||
setupIntegrationsScreen();
|
||||
break;
|
||||
case R.xml.preferences_flattr:
|
||||
setupFlattrScreen();
|
||||
break;
|
||||
case R.xml.preferences_gpodder:
|
||||
setupGpodderScreen();
|
||||
break;
|
||||
case R.xml.preferences_storage:
|
||||
setupStorageScreen();
|
||||
break;
|
||||
@ -300,7 +304,20 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
||||
}
|
||||
|
||||
private void setupIntegrationsScreen() {
|
||||
final Activity activity = ui.getActivity();
|
||||
final AppCompatActivity activity = ui.getActivity();
|
||||
|
||||
ui.findPreference(PREF_SCREEN_FLATTR).setOnPreferenceClickListener(preference -> {
|
||||
openScreen(R.xml.preferences_flattr, activity);
|
||||
return true;
|
||||
});
|
||||
ui.findPreference(PREF_SCREEN_GPODDER).setOnPreferenceClickListener(preference -> {
|
||||
openScreen(R.xml.preferences_gpodder, activity);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setupFlattrScreen() {
|
||||
final AppCompatActivity activity = ui.getActivity();
|
||||
|
||||
ui.findPreference(PreferenceController.PREF_FLATTR_REVOKE).setOnPreferenceClickListener(
|
||||
preference -> {
|
||||
@ -309,6 +326,29 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS)
|
||||
.setOnPreferenceClickListener(preference -> {
|
||||
AutoFlattrPreferenceDialog.newAutoFlattrPreferenceDialog(activity,
|
||||
new AutoFlattrPreferenceDialog.AutoFlattrPreferenceDialogInterface() {
|
||||
@Override
|
||||
public void onCancelled() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfirmed(boolean autoFlattrEnabled, float autoFlattrValue) {
|
||||
UserPreferences.setAutoFlattrSettings(autoFlattrEnabled, autoFlattrValue);
|
||||
checkFlattrItemVisibility();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setupGpodderScreen() {
|
||||
final AppCompatActivity activity = ui.getActivity();
|
||||
|
||||
ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION)
|
||||
.setOnPreferenceClickListener(preference -> {
|
||||
AuthenticationDialog dialog = new AuthenticationDialog(activity,
|
||||
@ -356,24 +396,6 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
||||
GpodnetSetHostnameDialog.createDialog(activity).setOnDismissListener(dialog -> updateGpodnetPreferenceScreen());
|
||||
return true;
|
||||
});
|
||||
|
||||
ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS)
|
||||
.setOnPreferenceClickListener(preference -> {
|
||||
AutoFlattrPreferenceDialog.newAutoFlattrPreferenceDialog(activity,
|
||||
new AutoFlattrPreferenceDialog.AutoFlattrPreferenceDialogInterface() {
|
||||
@Override
|
||||
public void onCancelled() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfirmed(boolean autoFlattrEnabled, float autoFlattrValue) {
|
||||
UserPreferences.setAutoFlattrSettings(autoFlattrEnabled, autoFlattrValue);
|
||||
checkFlattrItemVisibility();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setupPlaybackScreen() {
|
||||
@ -395,7 +417,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
||||
return true;
|
||||
});
|
||||
if (!PictureInPictureUtil.supportsPictureInPicture(activity)) {
|
||||
MaterialListPreference behaviour = (MaterialListPreference) ui.findPreference(UserPreferences.PREF_VIDEO_BEHAVIOR);
|
||||
ListPreference behaviour = (ListPreference) ui.findPreference(UserPreferences.PREF_VIDEO_BEHAVIOR);
|
||||
behaviour.setEntries(R.array.video_background_behavior_options_without_pip);
|
||||
behaviour.setEntryValues(R.array.video_background_behavior_values_without_pip);
|
||||
}
|
||||
@ -432,9 +454,11 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
||||
}
|
||||
|
||||
private void setupNetworkScreen() {
|
||||
final Activity activity = ui.getActivity();
|
||||
ui.findPreference(PREF_SCREEN_AUTODL).setOnPreferenceClickListener(preference ->
|
||||
openScreen(R.xml.preferences_autodownload, activity));
|
||||
final AppCompatActivity activity = ui.getActivity();
|
||||
ui.findPreference(PREF_SCREEN_AUTODL).setOnPreferenceClickListener(preference -> {
|
||||
openScreen(R.xml.preferences_autodownload, activity);
|
||||
return true;
|
||||
});
|
||||
ui.findPreference(UserPreferences.PREF_UPDATE_INTERVAL)
|
||||
.setOnPreferenceClickListener(preference -> {
|
||||
showUpdateIntervalTimePreferencesDialog();
|
||||
@ -458,33 +482,6 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
||||
}
|
||||
);
|
||||
// validate and set correct value: number of downloads between 1 and 50 (inclusive)
|
||||
final EditText ev = ((EditTextPreference) ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS)).getEditText();
|
||||
ev.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
if (s.length() > 0) {
|
||||
try {
|
||||
int value = Integer.parseInt(s.toString());
|
||||
if (value <= 0) {
|
||||
ev.setText("1");
|
||||
} else if (value > 50) {
|
||||
ev.setText("50");
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
ev.setText("6");
|
||||
}
|
||||
ev.setSelection(ev.getText().length());
|
||||
}
|
||||
}
|
||||
});
|
||||
ui.findPreference(PREF_PROXY).setOnPreferenceClickListener(preference -> {
|
||||
ProxyDialog dialog = new ProxyDialog(ui.getActivity());
|
||||
dialog.createDialog().show();
|
||||
@ -493,17 +490,28 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
||||
}
|
||||
|
||||
private void setupMainScreen() {
|
||||
final Activity activity = ui.getActivity();
|
||||
ui.findPreference(PREF_SCREEN_USER_INTERFACE).setOnPreferenceClickListener(preference ->
|
||||
openScreen(R.xml.preferences_user_interface, activity));
|
||||
ui.findPreference(PREF_SCREEN_PLAYBACK).setOnPreferenceClickListener(preference ->
|
||||
openScreen(R.xml.preferences_playback, activity));
|
||||
ui.findPreference(PREF_SCREEN_NETWORK).setOnPreferenceClickListener(preference ->
|
||||
openScreen(R.xml.preferences_network, activity));
|
||||
ui.findPreference(PREF_SCREEN_INTEGRATIONS).setOnPreferenceClickListener(preference ->
|
||||
openScreen(R.xml.preferences_integrations, activity));
|
||||
ui.findPreference(PREF_SCREEN_STORAGE).setOnPreferenceClickListener(preference ->
|
||||
openScreen(R.xml.preferences_storage, activity));
|
||||
final AppCompatActivity activity = ui.getActivity();
|
||||
setupSearch();
|
||||
ui.findPreference(PREF_SCREEN_USER_INTERFACE).setOnPreferenceClickListener(preference -> {
|
||||
openScreen(R.xml.preferences_user_interface, activity);
|
||||
return true;
|
||||
});
|
||||
ui.findPreference(PREF_SCREEN_PLAYBACK).setOnPreferenceClickListener(preference -> {
|
||||
openScreen(R.xml.preferences_playback, activity);
|
||||
return true;
|
||||
});
|
||||
ui.findPreference(PREF_SCREEN_NETWORK).setOnPreferenceClickListener(preference -> {
|
||||
openScreen(R.xml.preferences_network, activity);
|
||||
return true;
|
||||
});
|
||||
ui.findPreference(PREF_SCREEN_INTEGRATIONS).setOnPreferenceClickListener(preference -> {
|
||||
openScreen(R.xml.preferences_integrations, activity);
|
||||
return true;
|
||||
});
|
||||
ui.findPreference(PREF_SCREEN_STORAGE).setOnPreferenceClickListener(preference -> {
|
||||
openScreen(R.xml.preferences_storage, activity);
|
||||
return true;
|
||||
});
|
||||
|
||||
ui.findPreference(PreferenceController.PREF_ABOUT).setOnPreferenceClickListener(
|
||||
preference -> {
|
||||
@ -550,15 +558,74 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
||||
});
|
||||
}
|
||||
|
||||
private boolean openScreen(int preferences, Activity activity) {
|
||||
Fragment prefFragment = new PreferenceActivity.MainFragment();
|
||||
private void setupSearch() {
|
||||
final AppCompatActivity activity = ui.getActivity();
|
||||
|
||||
SearchPreference searchPreference = (SearchPreference) ui.findPreference("searchPreference");
|
||||
SearchConfiguration config = searchPreference.getSearchConfiguration();
|
||||
config.setActivity(activity);
|
||||
config.setFragmentContainerViewId(R.id.content);
|
||||
config.setBreadcrumbsEnabled(true);
|
||||
|
||||
config.index()
|
||||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_user_interface))
|
||||
.addFile(R.xml.preferences_user_interface);
|
||||
config.index()
|
||||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_playback))
|
||||
.addFile(R.xml.preferences_playback);
|
||||
config.index()
|
||||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_network))
|
||||
.addFile(R.xml.preferences_network);
|
||||
config.index()
|
||||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_storage))
|
||||
.addFile(R.xml.preferences_storage);
|
||||
config.index()
|
||||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_network))
|
||||
.addBreadcrumb(R.string.automation)
|
||||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_autodownload))
|
||||
.addFile(R.xml.preferences_autodownload);
|
||||
config.index()
|
||||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_integrations))
|
||||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_gpodder))
|
||||
.addFile(R.xml.preferences_gpodder);
|
||||
config.index()
|
||||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_integrations))
|
||||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_flattr))
|
||||
.addFile(R.xml.preferences_flattr);
|
||||
}
|
||||
|
||||
public PreferenceFragmentCompat openScreen(int preferences, AppCompatActivity activity) {
|
||||
PreferenceFragmentCompat prefFragment = new PreferenceActivity.MainFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(PARAM_RESOURCE, preferences);
|
||||
prefFragment.setArguments(args);
|
||||
activity.getFragmentManager().beginTransaction()
|
||||
activity.getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.content, prefFragment)
|
||||
.addToBackStack(TAG).commit();
|
||||
return true;
|
||||
return prefFragment;
|
||||
}
|
||||
|
||||
public static int getTitleOfPage(int preferences) {
|
||||
switch (preferences) {
|
||||
case R.xml.preferences_network:
|
||||
return R.string.network_pref;
|
||||
case R.xml.preferences_autodownload:
|
||||
return R.string.pref_automatic_download_title;
|
||||
case R.xml.preferences_playback:
|
||||
return R.string.playback_pref;
|
||||
case R.xml.preferences_storage:
|
||||
return R.string.storage_pref;
|
||||
case R.xml.preferences_user_interface:
|
||||
return R.string.user_interface_label;
|
||||
case R.xml.preferences_integrations:
|
||||
return R.string.integrations_label;
|
||||
case R.xml.preferences_flattr:
|
||||
return R.string.flattr_label;
|
||||
case R.xml.preferences_gpodder:
|
||||
return R.string.gpodnet_main_label;
|
||||
default:
|
||||
return R.string.settings_label;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean export(ExportWriter exportWriter) {
|
||||
@ -628,9 +695,14 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
||||
setDataFolderText();
|
||||
break;
|
||||
case R.xml.preferences_integrations:
|
||||
setIntegrationsItemVisibility();
|
||||
return;
|
||||
case R.xml.preferences_flattr:
|
||||
checkFlattrItemVisibility();
|
||||
break;
|
||||
case R.xml.preferences_gpodder:
|
||||
GpodnetPreferences.registerOnSharedPreferenceChangeListener(gpoddernetListener);
|
||||
updateGpodnetPreferenceScreen();
|
||||
checkFlattrItemVisibility();
|
||||
break;
|
||||
case R.xml.preferences_playback:
|
||||
checkSonicItemVisibility();
|
||||
@ -797,10 +869,13 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
||||
}
|
||||
}
|
||||
|
||||
private void setIntegrationsItemVisibility() {
|
||||
ui.findPreference(PreferenceController.PREF_SCREEN_FLATTR).setEnabled(FlattrUtils.hasAPICredentials());
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void checkFlattrItemVisibility() {
|
||||
boolean hasFlattrToken = FlattrUtils.hasToken();
|
||||
ui.findPreference(PreferenceController.PREF_FLATTR_SETTINGS).setEnabled(FlattrUtils.hasAPICredentials());
|
||||
ui.findPreference(PreferenceController.PREF_FLATTR_AUTH).setEnabled(!hasFlattrToken);
|
||||
ui.findPreference(PreferenceController.PREF_FLATTR_REVOKE).setEnabled(hasFlattrToken);
|
||||
ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS).setEnabled(hasFlattrToken);
|
||||
@ -1115,7 +1190,8 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
||||
|
||||
public interface PreferenceUI {
|
||||
|
||||
void setFragment(PreferenceFragment fragment);
|
||||
void setFragment(PreferenceFragmentCompat fragment);
|
||||
PreferenceFragmentCompat getFragment();
|
||||
|
||||
/**
|
||||
* Finds a preference based on its key.
|
||||
@ -1124,6 +1200,6 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
||||
|
||||
PreferenceScreen getPreferenceScreen();
|
||||
|
||||
Activity getActivity();
|
||||
AppCompatActivity getActivity();
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +0,0 @@
|
||||
package de.danoeh.antennapod.preferences;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
|
||||
public class SwitchCompatPreference extends CheckBoxPreference {
|
||||
|
||||
public SwitchCompatPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public SwitchCompatPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init();
|
||||
}
|
||||
|
||||
public SwitchCompatPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public SwitchCompatPreference(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setWidgetLayoutResource(R.layout.preference_switch_layout);
|
||||
}
|
||||
}
|
@ -1,244 +0,0 @@
|
||||
package de.danoeh.antennapod.service;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
import de.danoeh.antennapod.fragment.QueueFragment;
|
||||
import de.danoeh.antennapod.receiver.PlayerWidget;
|
||||
|
||||
/**
|
||||
* Updates the state of the player widget
|
||||
*/
|
||||
public class PlayerWidgetService extends Service {
|
||||
private static final String TAG = "PlayerWidgetService";
|
||||
|
||||
private PlaybackService playbackService;
|
||||
|
||||
/**
|
||||
* Controls write access to playbackservice reference
|
||||
*/
|
||||
private final Object psLock = new Object();
|
||||
|
||||
/**
|
||||
* True while service is updating the widget
|
||||
*/
|
||||
private volatile boolean isUpdating;
|
||||
|
||||
public PlayerWidgetService() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Log.d(TAG, "Service created");
|
||||
isUpdating = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
Log.d(TAG, "Service is about to be destroyed");
|
||||
if (playbackService != null) {
|
||||
Playable playable = playbackService.getPlayable();
|
||||
if (playable != null && playable instanceof FeedMedia) {
|
||||
FeedMedia media = (FeedMedia) playable;
|
||||
if (media.hasAlmostEnded()) {
|
||||
Log.d(TAG, "smart mark as read");
|
||||
FeedItem item = media.getItem();
|
||||
DBWriter.markItemPlayed(item, FeedItem.PLAYED, false);
|
||||
DBWriter.removeQueueItem(this, item, false);
|
||||
DBWriter.addItemToPlaybackHistory(media);
|
||||
if (item.getFeed().getPreferences().getCurrentAutoDelete() &&
|
||||
(!item.isTagged(FeedItem.TAG_FAVORITE) || !UserPreferences.shouldFavoriteKeepEpisode())) {
|
||||
Log.d(TAG, "Delete " + media.toString());
|
||||
DBWriter.deleteFeedMediaOfItem(this, media.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
unbindService(mConnection);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.w(TAG, "IllegalArgumentException when trying to unbind service");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (!isUpdating) {
|
||||
if (playbackService == null && PlaybackService.isRunning) {
|
||||
bindService(new Intent(this, PlaybackService.class),
|
||||
mConnection, 0);
|
||||
} else {
|
||||
startViewUpdaterIfNotRunning();
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Service was called while updating. Ignoring update request");
|
||||
}
|
||||
return Service.START_NOT_STICKY;
|
||||
}
|
||||
|
||||
private void updateViews() {
|
||||
isUpdating = true;
|
||||
|
||||
ComponentName playerWidget = new ComponentName(this, PlayerWidget.class);
|
||||
AppWidgetManager manager = AppWidgetManager.getInstance(this);
|
||||
RemoteViews views = new RemoteViews(getPackageName(),
|
||||
R.layout.player_widget);
|
||||
PendingIntent startMediaplayer = PendingIntent.getActivity(this, 0,
|
||||
PlaybackService.getPlayerActivityIntent(this), 0);
|
||||
|
||||
Intent startApp = new Intent(getBaseContext(), MainActivity.class);
|
||||
startApp.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startApp.putExtra(MainActivity.EXTRA_FRAGMENT_TAG, QueueFragment.TAG);
|
||||
PendingIntent startAppPending = PendingIntent.getActivity(getBaseContext(), 0, startApp, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
boolean nothingPlaying = false;
|
||||
if (playbackService != null) {
|
||||
final Playable media = playbackService.getPlayable();
|
||||
if (media != null) {
|
||||
PlayerStatus status = playbackService.getStatus();
|
||||
views.setOnClickPendingIntent(R.id.layout_left, startMediaplayer);
|
||||
|
||||
views.setTextViewText(R.id.txtvTitle, media.getEpisodeTitle());
|
||||
|
||||
String progressString = getProgressString();
|
||||
if (progressString != null) {
|
||||
views.setViewVisibility(R.id.txtvProgress, View.VISIBLE);
|
||||
views.setTextViewText(R.id.txtvProgress, progressString);
|
||||
}
|
||||
|
||||
if (status == PlayerStatus.PLAYING) {
|
||||
views.setImageViewResource(R.id.butPlay, R.drawable.ic_pause_white_24dp);
|
||||
if (Build.VERSION.SDK_INT >= 15) {
|
||||
views.setContentDescription(R.id.butPlay, getString(R.string.pause_label));
|
||||
}
|
||||
} else {
|
||||
views.setImageViewResource(R.id.butPlay, R.drawable.ic_play_arrow_white_24dp);
|
||||
if (Build.VERSION.SDK_INT >= 15) {
|
||||
views.setContentDescription(R.id.butPlay, getString(R.string.play_label));
|
||||
}
|
||||
}
|
||||
views.setOnClickPendingIntent(R.id.butPlay,
|
||||
createMediaButtonIntent());
|
||||
} else {
|
||||
nothingPlaying = true;
|
||||
}
|
||||
} else {
|
||||
nothingPlaying = true;
|
||||
}
|
||||
|
||||
if (nothingPlaying) {
|
||||
// start the app if they click anything
|
||||
views.setOnClickPendingIntent(R.id.layout_left, startAppPending);
|
||||
views.setOnClickPendingIntent(R.id.butPlay, startAppPending);
|
||||
views.setViewVisibility(R.id.txtvProgress, View.INVISIBLE);
|
||||
views.setTextViewText(R.id.txtvTitle,
|
||||
this.getString(R.string.no_media_playing_label));
|
||||
views.setImageViewResource(R.id.butPlay, R.drawable.ic_play_arrow_white_24dp);
|
||||
}
|
||||
|
||||
manager.updateAppWidget(playerWidget, views);
|
||||
isUpdating = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an intent which fakes a mediabutton press
|
||||
*/
|
||||
private PendingIntent createMediaButtonIntent() {
|
||||
KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN,
|
||||
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
|
||||
Intent startingIntent = new Intent(
|
||||
MediaButtonReceiver.NOTIFY_BUTTON_RECEIVER);
|
||||
startingIntent.putExtra(Intent.EXTRA_KEY_EVENT, event);
|
||||
|
||||
return PendingIntent.getBroadcast(this, 0, startingIntent, 0);
|
||||
}
|
||||
|
||||
private String getProgressString() {
|
||||
int position = playbackService.getCurrentPosition();
|
||||
int duration = playbackService.getDuration();
|
||||
if (position > 0 && duration > 0) {
|
||||
return Converter.getDurationStringLong(position) + " / "
|
||||
+ Converter.getDurationStringLong(duration);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private final ServiceConnection mConnection = new ServiceConnection() {
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
Log.d(TAG, "Connection to service established");
|
||||
synchronized (psLock) {
|
||||
if(service instanceof PlaybackService.LocalBinder) {
|
||||
playbackService = ((PlaybackService.LocalBinder) service).getService();
|
||||
startViewUpdaterIfNotRunning();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
synchronized (psLock) {
|
||||
playbackService = null;
|
||||
Log.d(TAG, "Disconnected from service");
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private void startViewUpdaterIfNotRunning() {
|
||||
if (!isUpdating) {
|
||||
ViewUpdater updateThread = new ViewUpdater(this);
|
||||
updateThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
class ViewUpdater extends Thread {
|
||||
private static final String THREAD_NAME = "ViewUpdater";
|
||||
private final PlayerWidgetService service;
|
||||
|
||||
public ViewUpdater(PlayerWidgetService service) {
|
||||
super();
|
||||
setName(THREAD_NAME);
|
||||
this.service = service;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (psLock) {
|
||||
service.updateViews();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/webvContainer"
|
||||
android:id="@+id/webViewContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webvAbout"
|
||||
android:id="@+id/webViewAbout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
|
@ -44,6 +44,7 @@
|
||||
android:layout_centerVertical="true"
|
||||
android:contentDescription="@string/pause_label"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:src="?attr/av_play_big"
|
||||
tools:src="@drawable/ic_play_arrow_white_36dp"/>
|
||||
|
||||
<TextView
|
||||
|
@ -110,9 +110,9 @@
|
||||
android:layout_centerHorizontal="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:contentDescription="@string/pause_label"
|
||||
android:src="?attr/av_pause"
|
||||
android:src="?attr/av_play"
|
||||
android:scaleType="fitCenter"
|
||||
tools:src="@drawable/ic_pause_white_36dp"
|
||||
tools:src="@drawable/ic_play_arrow_white_24dp"
|
||||
tools:background="@android:color/holo_green_dark" />
|
||||
|
||||
<ImageButton
|
||||
|
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.v7.widget.SwitchCompat
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@null"
|
||||
android:clickable="false"
|
||||
android:focusable="false" />
|
@ -1,10 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<com.bytehamster.lib.preferencesearch.SearchPreference
|
||||
android:key="searchPreference" />
|
||||
|
||||
<Preference
|
||||
android:key="prefScreenInterface"
|
||||
android:title="@string/user_interface_label"
|
||||
android:icon="?attr/type_video" />
|
||||
android:key="prefScreenInterface"
|
||||
android:title="@string/user_interface_label"
|
||||
android:icon="?attr/type_video" />
|
||||
|
||||
<Preference
|
||||
android:key="prefScreenPlayback"
|
||||
|
@ -1,20 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:search="http://schemas.android.com/apk/com.bytehamster.lib.preferencesearch">
|
||||
|
||||
<de.danoeh.antennapod.preferences.MasterSwitchPreference
|
||||
android:key="prefEnableAutoDl"
|
||||
android:title="@string/pref_automatic_download_title"
|
||||
search:summary="@string/pref_automatic_download_sum"
|
||||
android:defaultValue="false"/>
|
||||
<com.afollestad.materialdialogs.prefs.MaterialListPreference
|
||||
<ListPreference
|
||||
android:defaultValue="25"
|
||||
android:entries="@array/episode_cache_size_entries"
|
||||
android:key="prefEpisodeCacheSize"
|
||||
android:title="@string/pref_episode_cache_title"
|
||||
android:entryValues="@array/episode_cache_size_values"
|
||||
app:useStockLayout="true"/>
|
||||
<com.afollestad.materialdialogs.prefs.MaterialListPreference
|
||||
<ListPreference
|
||||
android:defaultValue="-1"
|
||||
android:entries="@array/episode_cleanup_entries"
|
||||
android:key="prefEpisodeCleanup"
|
||||
@ -22,17 +24,17 @@
|
||||
android:summary="@string/pref_episode_cleanup_summary"
|
||||
android:entryValues="@array/episode_cleanup_values"
|
||||
app:useStockLayout="true"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:key="prefEnableAutoDownloadOnBattery"
|
||||
android:title="@string/pref_automatic_download_on_battery_title"
|
||||
android:summary="@string/pref_automatic_download_on_battery_sum"
|
||||
android:defaultValue="true"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:key="prefEnableAutoDownloadOnMobile"
|
||||
android:title="@string/pref_autodl_allow_on_mobile_title"
|
||||
android:summary="@string/pref_autodl_allow_on_mobile_sum"
|
||||
android:defaultValue="false"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:key="prefEnableAutoDownloadWifiFilter"
|
||||
android:title="@string/pref_autodl_wifi_filter_title"
|
||||
android:summary="@string/pref_autodl_wifi_filter_sum"/>
|
||||
|
21
app/src/main/res/xml/preferences_flattr.xml
Normal file
21
app/src/main/res/xml/preferences_flattr.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<PreferenceScreen
|
||||
android:key="pref_flattr_authenticate"
|
||||
android:summary="@string/pref_flattr_auth_sum"
|
||||
android:title="@string/pref_flattr_auth_title">
|
||||
<intent android:action=".activities.FlattrAuthActivity"/>
|
||||
</PreferenceScreen>
|
||||
|
||||
<Preference
|
||||
android:key="prefAutoFlattrPrefs"
|
||||
android:summary="@string/pref_auto_flattr_sum"
|
||||
android:title="@string/pref_auto_flattr_title"/>
|
||||
<Preference
|
||||
android:key="prefRevokeAccess"
|
||||
android:summary="@string/pref_revokeAccess_sum"
|
||||
android:title="@string/pref_revokeAccess_title"/>
|
||||
|
||||
</PreferenceScreen>
|
35
app/src/main/res/xml/preferences_gpodder.xml
Normal file
35
app/src/main/res/xml/preferences_gpodder.xml
Normal file
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<PreferenceScreen
|
||||
android:key="pref_gpodnet_authenticate"
|
||||
android:title="@string/pref_gpodnet_authenticate_title"
|
||||
android:summary="@string/pref_gpodnet_authenticate_sum">
|
||||
<intent android:action=".activity.gpoddernet.GpodnetAuthenticationActivity"/>
|
||||
</PreferenceScreen>
|
||||
<Preference
|
||||
android:key="pref_gpodnet_setlogin_information"
|
||||
android:title="@string/pref_gpodnet_setlogin_information_title"
|
||||
android:summary="@string/pref_gpodnet_setlogin_information_sum"/>
|
||||
<Preference
|
||||
android:key="pref_gpodnet_sync"
|
||||
android:title="@string/pref_gpodnet_sync_changes_title"
|
||||
android:summary="@string/pref_gpodnet_sync_changes_sum"/>
|
||||
<Preference
|
||||
android:key="pref_gpodnet_force_full_sync"
|
||||
android:title="@string/pref_gpodnet_full_sync_title"
|
||||
android:summary="@string/pref_gpodnet_full_sync_sum"/>
|
||||
<Preference
|
||||
android:key="pref_gpodnet_logout"
|
||||
android:title="@string/pref_gpodnet_logout_title"/>
|
||||
<Preference
|
||||
android:key="pref_gpodnet_hostname"
|
||||
android:title="@string/pref_gpodnet_sethostname_title"/>
|
||||
<SwitchPreference
|
||||
android:key="pref_gpodnet_notifications"
|
||||
android:title="@string/pref_gpodnet_notifications_title"
|
||||
android:summary="@string/pref_gpodnet_notifications_sum"
|
||||
android:defaultValue="true"/>
|
||||
|
||||
</PreferenceScreen>
|
@ -3,61 +3,14 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceScreen
|
||||
<Preference
|
||||
android:key="prefFlattrSettings"
|
||||
android:title="@string/flattr_label"
|
||||
android:summary="@string/flattr_summary">
|
||||
<PreferenceScreen
|
||||
android:key="pref_flattr_authenticate"
|
||||
android:summary="@string/pref_flattr_auth_sum"
|
||||
android:title="@string/pref_flattr_auth_title">
|
||||
<intent android:action=".activities.FlattrAuthActivity"/>
|
||||
</PreferenceScreen>
|
||||
android:summary="@string/flattr_summary" />
|
||||
|
||||
<Preference
|
||||
android:key="prefAutoFlattrPrefs"
|
||||
android:summary="@string/pref_auto_flattr_sum"
|
||||
android:title="@string/pref_auto_flattr_title"/>
|
||||
<Preference
|
||||
android:key="prefRevokeAccess"
|
||||
android:summary="@string/pref_revokeAccess_sum"
|
||||
android:title="@string/pref_revokeAccess_title"/>
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
<Preference
|
||||
android:key="prefGpodderSettings"
|
||||
android:title="@string/gpodnet_main_label"
|
||||
android:summary="@string/gpodnet_summary">
|
||||
|
||||
<PreferenceScreen
|
||||
android:key="pref_gpodnet_authenticate"
|
||||
android:title="@string/pref_gpodnet_authenticate_title"
|
||||
android:summary="@string/pref_gpodnet_authenticate_sum">
|
||||
<intent android:action=".activity.gpoddernet.GpodnetAuthenticationActivity"/>
|
||||
</PreferenceScreen>
|
||||
<Preference
|
||||
android:key="pref_gpodnet_setlogin_information"
|
||||
android:title="@string/pref_gpodnet_setlogin_information_title"
|
||||
android:summary="@string/pref_gpodnet_setlogin_information_sum"/>
|
||||
<Preference
|
||||
android:key="pref_gpodnet_sync"
|
||||
android:title="@string/pref_gpodnet_sync_changes_title"
|
||||
android:summary="@string/pref_gpodnet_sync_changes_sum"/>
|
||||
<Preference
|
||||
android:key="pref_gpodnet_force_full_sync"
|
||||
android:title="@string/pref_gpodnet_full_sync_title"
|
||||
android:summary="@string/pref_gpodnet_full_sync_sum"/>
|
||||
<Preference
|
||||
android:key="pref_gpodnet_logout"
|
||||
android:title="@string/pref_gpodnet_logout_title"/>
|
||||
<Preference
|
||||
android:key="pref_gpodnet_hostname"
|
||||
android:title="@string/pref_gpodnet_sethostname_title"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
android:key="pref_gpodnet_notifications"
|
||||
android:title="@string/pref_gpodnet_notifications_title"
|
||||
android:summary="@string/pref_gpodnet_notifications_sum"
|
||||
android:defaultValue="true"/>
|
||||
</PreferenceScreen>
|
||||
android:summary="@string/gpodnet_summary" />
|
||||
|
||||
</PreferenceScreen>
|
||||
|
@ -1,13 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:search="http://schemas.android.com/apk/com.bytehamster.lib.preferencesearch">
|
||||
<PreferenceCategory android:title="@string/automation">
|
||||
<Preference
|
||||
android:key="prefAutoUpdateIntervall"
|
||||
android:summary="@string/pref_autoUpdateIntervallOrTime_sum"
|
||||
android:title="@string/pref_autoUpdateIntervallOrTime_title"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:enabled="true"
|
||||
android:key="prefMobileUpdate"
|
||||
@ -16,17 +17,18 @@
|
||||
<Preference
|
||||
android:summary="@string/pref_automatic_download_sum"
|
||||
android:key="prefAutoDownloadSettings"
|
||||
android:title="@string/pref_automatic_download_title" />
|
||||
android:title="@string/pref_automatic_download_title"
|
||||
search:ignore="true" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/download_pref_details">
|
||||
<com.afollestad.materialdialogs.prefs.MaterialEditTextPreference
|
||||
<EditTextPreference
|
||||
android:defaultValue="4"
|
||||
android:inputType="number"
|
||||
android:key="prefParallelDownloads"
|
||||
android:title="@string/pref_parallel_downloads_title"
|
||||
app:useStockLayout="true"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:enabled="true"
|
||||
android:key="prefShowDownloadReport"
|
||||
|
@ -4,39 +4,39 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceCategory android:title="@string/interruptions">
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:enabled="true"
|
||||
android:key="prefPauseOnHeadsetDisconnect"
|
||||
android:summary="@string/pref_pauseOnDisconnect_sum"
|
||||
android:title="@string/pref_pauseOnHeadsetDisconnect_title"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:enabled="true"
|
||||
android:dependency="prefPauseOnHeadsetDisconnect"
|
||||
android:key="prefUnpauseOnHeadsetReconnect"
|
||||
android:summary="@string/pref_unpauseOnHeadsetReconnect_sum"
|
||||
android:title="@string/pref_unpauseOnHeadsetReconnect_title"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:enabled="true"
|
||||
android:dependency="prefPauseOnHeadsetDisconnect"
|
||||
android:key="prefUnpauseOnBluetoothReconnect"
|
||||
android:summary="@string/pref_unpauseOnBluetoothReconnect_sum"
|
||||
android:title="@string/pref_unpauseOnBluetoothReconnect_title"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:enabled="true"
|
||||
android:key="prefPauseForFocusLoss"
|
||||
android:summary="@string/pref_pausePlaybackForFocusLoss_sum"
|
||||
android:title="@string/pref_pausePlaybackForFocusLoss_title"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:enabled="true"
|
||||
android:key="prefResumeAfterCall"
|
||||
android:summary="@string/pref_resumeAfterCall_sum"
|
||||
android:title="@string/pref_resumeAfterCall_title"/>
|
||||
<com.afollestad.materialdialogs.prefs.MaterialListPreference
|
||||
<ListPreference
|
||||
android:defaultValue="stop"
|
||||
android:entries="@array/video_background_behavior_options"
|
||||
android:entryValues="@array/video_background_behavior_values"
|
||||
@ -47,13 +47,13 @@
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/buttons">
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:enabled="true"
|
||||
android:key="prefHardwareForwardButtonSkips"
|
||||
android:summary="@string/pref_hardwareForwardButtonSkips_sum"
|
||||
android:title="@string/pref_hardwareForwardButtonSkips_title"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:enabled="true"
|
||||
android:key="prefHardwarePreviousButtonRestarts"
|
||||
@ -74,25 +74,25 @@
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/queue_label">
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:enabled="true"
|
||||
android:key="prefEnqueueDownloaded"
|
||||
android:summary="@string/pref_enqueue_downloaded_summary"
|
||||
android:title="@string/pref_enqueue_downloaded_title" />
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:enabled="true"
|
||||
android:key="prefQueueAddToFront"
|
||||
android:summary="@string/pref_queueAddToFront_sum"
|
||||
android:title="@string/pref_queueAddToFront_title"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:enabled="true"
|
||||
android:key="prefFollowQueue"
|
||||
android:summary="@string/pref_followQueue_sum"
|
||||
android:title="@string/pref_followQueue_title"/>
|
||||
<com.afollestad.materialdialogs.prefs.MaterialListPreference
|
||||
<ListPreference
|
||||
android:defaultValue="30"
|
||||
android:entries="@array/smart_mark_as_played_values"
|
||||
android:entryValues="@array/smart_mark_as_played_values"
|
||||
@ -100,7 +100,7 @@
|
||||
android:summary="@string/pref_smart_mark_as_played_sum"
|
||||
android:title="@string/pref_smart_mark_as_played_title"
|
||||
app:useStockLayout="true"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:enabled="true"
|
||||
android:key="prefSkipKeepsEpisode"
|
||||
@ -109,7 +109,7 @@
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/media_player">
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:enabled="false"
|
||||
android:key="prefSonic"
|
||||
@ -118,7 +118,7 @@
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/experimental_pref">
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:enabled="true"
|
||||
android:key="prefCast"
|
||||
|
@ -13,13 +13,13 @@
|
||||
android:key="prefImageCacheSize"
|
||||
android:summary="@string/pref_image_cache_size_sum"
|
||||
android:defaultValue="100"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:enabled="true"
|
||||
android:key="prefAutoDelete"
|
||||
android:summary="@string/pref_auto_delete_sum"
|
||||
android:title="@string/pref_auto_delete_title"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:enabled="true"
|
||||
android:key="prefFavoriteKeepsEpisode"
|
||||
|
@ -4,7 +4,7 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceCategory android:title="@string/appearance">
|
||||
<com.afollestad.materialdialogs.prefs.MaterialListPreference
|
||||
<ListPreference
|
||||
android:entryValues="@array/theme_values"
|
||||
android:entries="@array/theme_options"
|
||||
android:title="@string/pref_set_theme_title"
|
||||
@ -16,7 +16,7 @@
|
||||
android:key="prefHiddenDrawerItems"
|
||||
android:summary="@string/pref_nav_drawer_items_sum"
|
||||
android:title="@string/pref_nav_drawer_items_title"/>
|
||||
<com.afollestad.materialdialogs.prefs.MaterialListPreference
|
||||
<ListPreference
|
||||
android:entryValues="@array/nav_drawer_feed_order_values"
|
||||
android:entries="@array/nav_drawer_feed_order_options"
|
||||
android:title="@string/pref_nav_drawer_feed_order_title"
|
||||
@ -24,7 +24,7 @@
|
||||
android:summary="@string/pref_nav_drawer_feed_order_sum"
|
||||
android:defaultValue="0"
|
||||
app:useStockLayout="true"/>
|
||||
<com.afollestad.materialdialogs.prefs.MaterialListPreference
|
||||
<ListPreference
|
||||
android:entryValues="@array/nav_drawer_feed_counter_values"
|
||||
android:entries="@array/nav_drawer_feed_counter_options"
|
||||
android:title="@string/pref_nav_drawer_feed_counter_title"
|
||||
@ -34,13 +34,13 @@
|
||||
app:useStockLayout="true"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/external_elements">
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:enabled="true"
|
||||
android:key="prefExpandNotify"
|
||||
android:summary="@string/pref_expandNotify_sum"
|
||||
android:title="@string/pref_expandNotify_title"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:enabled="true"
|
||||
android:key="prefPersistNotify"
|
||||
@ -50,7 +50,7 @@
|
||||
android:key="prefCompactNotificationButtons"
|
||||
android:summary="@string/pref_compact_notification_buttons_sum"
|
||||
android:title="@string/pref_compact_notification_buttons_title"/>
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:enabled="true"
|
||||
android:key="prefLockscreenBackground"
|
||||
|
@ -37,12 +37,12 @@ subprojects {
|
||||
}
|
||||
|
||||
project.ext {
|
||||
compileSdkVersion = 25
|
||||
compileSdkVersion = 26
|
||||
buildToolsVersion = "27.0.3"
|
||||
minSdkVersion = 14
|
||||
targetSdkVersion = 26
|
||||
|
||||
supportVersion = "25.3.1"
|
||||
supportVersion = "26.1.0"
|
||||
commonsioVersion = "2.5"
|
||||
commonslangVersion = "3.6"
|
||||
commonstextVersion = "1.3"
|
||||
@ -66,7 +66,7 @@ project.ext {
|
||||
|
||||
castCompanionLibVer = "2.9.1"
|
||||
playServicesVersion = "8.4.0"
|
||||
wearableSupportVersion = "2.0.3"
|
||||
wearableSupportVersion = "2.2.0"
|
||||
}
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
|
23
circle.yml
23
circle.yml
@ -1,23 +0,0 @@
|
||||
general:
|
||||
artifacts:
|
||||
- app/build/outputs/apk
|
||||
machine:
|
||||
environment:
|
||||
GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx1536m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError"'
|
||||
_JAVA_OPTIONS: "-Xms256m -Xmx1280m -XX:MaxPermSize=350m"
|
||||
java:
|
||||
version: oraclejdk8
|
||||
dependencies:
|
||||
cache_directories:
|
||||
- ~/.android
|
||||
- ~/android
|
||||
pre:
|
||||
- echo y | android update sdk --no-ui --all --filter "tool,extra-android-m2repository,extra-android-support,extra-google-google_play_services,extra-google-m2repository,android-25"
|
||||
- echo y | android update sdk --no-ui --all --filter "build-tools-27.0.3"
|
||||
override:
|
||||
- echo override dependencies
|
||||
|
||||
test:
|
||||
override:
|
||||
- ./gradlew assembleDebug -PdisablePreDex:
|
||||
timeout: 1800
|
@ -10,7 +10,7 @@ android {
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testApplicationId "de.danoeh.antennapod.core.tests"
|
||||
testInstrumentationRunner "de.danoeh.antennapod.core.tests.AntennaPodTestRunner"
|
||||
testInstrumentationRunner "de.danoeh.antennapod.core.AntennaPodTestRunner"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
@ -49,6 +49,8 @@ repositories {
|
||||
dependencies {
|
||||
implementation "com.android.support:support-v4:$supportVersion"
|
||||
implementation "com.android.support:appcompat-v7:$supportVersion"
|
||||
implementation "com.android.support:preference-v14:$supportVersion"
|
||||
implementation "com.android.support:percent:$supportVersion"
|
||||
implementation "org.apache.commons:commons-lang3:$commonslangVersion"
|
||||
implementation "org.apache.commons:commons-text:$commonstextVersion"
|
||||
implementation ("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") {
|
||||
@ -77,6 +79,18 @@ dependencies {
|
||||
} else {
|
||||
System.out.println("core: free build hack, skipping some dependencies")
|
||||
}
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
|
||||
}
|
||||
|
||||
tasks.withType(Test) {
|
||||
testLogging {
|
||||
exceptionFormat "full"
|
||||
events "skipped", "passed", "failed"
|
||||
showStandardStreams true
|
||||
displayGranularity 2
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
|
@ -1,4 +1,4 @@
|
||||
package de.danoeh.antennapod.core.tests;
|
||||
package de.danoeh.antennapod.core;
|
||||
|
||||
import android.test.InstrumentationTestRunner;
|
||||
import android.test.suitebuilder.TestSuiteBuilder;
|
@ -1,9 +0,0 @@
|
||||
package de.danoeh.antennapod.core.feed;
|
||||
|
||||
class FeedImageMother {
|
||||
|
||||
public static FeedImage anyFeedImage() {
|
||||
return new FeedImage(0, "image", null, "http://example.com/picture", false);
|
||||
}
|
||||
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package de.danoeh.antennapod.core.tests.util.service.download;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.service.download.DownloadService;
|
||||
|
||||
public class DownloadServiceTest extends AndroidTestCase {
|
||||
|
||||
public void testRemoveDuplicateImages() {
|
||||
List<FeedItem> items = new ArrayList<>();
|
||||
for (int i = 0; i < 50; i++) {
|
||||
FeedItem item = new FeedItem();
|
||||
String url = (i % 5 == 0) ? "dupe_url" : String.format("url_%d", i);
|
||||
item.setImage(new FeedImage(null, url, ""));
|
||||
items.add(item);
|
||||
}
|
||||
Feed feed = new Feed();
|
||||
feed.setItems(items);
|
||||
|
||||
DownloadService.removeDuplicateImages(feed);
|
||||
|
||||
assertEquals(50, items.size());
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
FeedItem item = items.get(i);
|
||||
String want = (i == 0) ? "dupe_url" : (i % 5 == 0) ? null : String.format("url_%d", i);
|
||||
assertEquals(want, item.getImageLocation());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package de.danoeh.antennapod.core.tests.util;
|
||||
package de.danoeh.antennapod.core.util;
|
||||
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
@ -7,8 +7,14 @@ import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import de.danoeh.antennapod.core.util.DateUtils;
|
||||
|
||||
/**
|
||||
* Unit test for {@link DateUtils}.
|
||||
*
|
||||
* Note: It NEEDS to be run in android devices, i.e., it cannot be run in standard JDK, because
|
||||
* the test invokes some android platform-specific behavior in the underlying
|
||||
* {@link java.text.SimpleDateFormat} used by {@link DateUtils}.
|
||||
*
|
||||
*/
|
||||
public class DateUtilsTest extends AndroidTestCase {
|
||||
|
||||
public void testParseDateWithMicroseconds() throws Exception {
|
||||
@ -101,6 +107,12 @@ public class DateUtilsTest extends AndroidTestCase {
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires Android platform.
|
||||
*
|
||||
* Reason: Standard JDK cannot parse timezone <code>-08:00</code> (ISO 8601 format). It only accepts
|
||||
* <code>-0800</code> (RFC 822 format)
|
||||
*/
|
||||
public void testParseDateWithNoTimezonePadding() throws Exception {
|
||||
GregorianCalendar exp = new GregorianCalendar(2017, 1, 22, 22, 28, 0);
|
||||
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
@ -109,6 +121,12 @@ public class DateUtilsTest extends AndroidTestCase {
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires Android platform. Root cause: {@link DateUtils} implementation makes
|
||||
* use of ISO 8601 time zone, which does not work on standard JDK.
|
||||
*
|
||||
* @see #testParseDateWithNoTimezonePadding()
|
||||
*/
|
||||
public void testParseDateWithForCest() throws Exception {
|
||||
GregorianCalendar exp1 = new GregorianCalendar(2017, 0, 28, 22, 0, 0);
|
||||
exp1.setTimeZone(TimeZone.getTimeZone("UTC"));
|
@ -27,6 +27,7 @@
|
||||
</service>
|
||||
<service
|
||||
android:name=".service.GpodnetSyncService"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE"
|
||||
android:enabled="true" />
|
||||
|
||||
<receiver
|
||||
@ -52,9 +53,17 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".receiver.FeedUpdateReceiver">
|
||||
<receiver android:name=".receiver.FeedUpdateReceiver"
|
||||
android:label="@string/feed_update_receiver_name"
|
||||
android:exported="true"> <!-- allow feeds update to be triggered by external apps -->
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name=".service.FeedUpdateJobService"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" >
|
||||
|
||||
</service>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
@ -14,7 +14,6 @@ import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
@ -64,29 +63,6 @@ class UpdateManager {
|
||||
}
|
||||
|
||||
private static void onUpgrade(final int oldVersionCode, final int newVersionCode) {
|
||||
if(oldVersionCode < 1030099) {
|
||||
// delete the now obsolete image cache
|
||||
// from now on, Glide will handle caching images
|
||||
new Thread() {
|
||||
public void run() {
|
||||
List<Feed> feeds = DBReader.getFeedList();
|
||||
for (Feed podcast : feeds) {
|
||||
List<FeedItem> episodes = DBReader.getFeedItemList(podcast);
|
||||
for (FeedItem episode : episodes) {
|
||||
FeedImage image = episode.getImage();
|
||||
if (image != null && image.isDownloaded() && image.getFile_url() != null) {
|
||||
File imageFile = new File(image.getFile_url());
|
||||
if (imageFile.exists()) {
|
||||
imageFile.delete();
|
||||
}
|
||||
image.setFile_url(null); // calls setDownloaded(false)
|
||||
DBWriter.setFeedImage(image);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
if(oldVersionCode < 1050004) {
|
||||
if(MediaPlayer.isPrestoLibraryInstalled(context) && Build.VERSION.SDK_INT >= 16) {
|
||||
UserPreferences.enableSonic(true);
|
||||
|
@ -10,6 +10,7 @@ import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
|
||||
import org.shredzone.flattr4j.exception.FlattrException;
|
||||
|
||||
import java.util.LinkedList;
|
||||
@ -175,7 +176,7 @@ public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorke
|
||||
PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
|
||||
ClientConfig.flattrCallbacks.getFlattrAuthenticationActivityIntent(context), 0);
|
||||
|
||||
Notification notification = new NotificationCompat.Builder(context)
|
||||
Notification notification = new NotificationCompat.Builder(context, NotificationUtils.CHANNEL_ID_ERROR)
|
||||
.setStyle(new NotificationCompat.BigTextStyle().bigText(context.getString(R.string.no_flattr_token_notification_msg)))
|
||||
.setContentIntent(contentIntent)
|
||||
.setContentTitle(context.getString(R.string.no_flattr_token_title))
|
||||
@ -208,7 +209,7 @@ public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorke
|
||||
+ context.getString(R.string.flattr_click_failure_count, failed);
|
||||
}
|
||||
|
||||
Notification notification = new NotificationCompat.Builder(context)
|
||||
Notification notification = new NotificationCompat.Builder(context, NotificationUtils.CHANNEL_ID_ERROR)
|
||||
.setStyle(new NotificationCompat.BigTextStyle().bigText(subtext))
|
||||
.setContentIntent(contentIntent)
|
||||
.setContentTitle(title)
|
||||
|
@ -0,0 +1,13 @@
|
||||
package de.danoeh.antennapod.core.event;
|
||||
|
||||
public class ServiceEvent {
|
||||
public enum Action {
|
||||
SERVICE_STARTED
|
||||
}
|
||||
|
||||
public final Action action;
|
||||
|
||||
public ServiceEvent(Action action) {
|
||||
this.action = action;
|
||||
}
|
||||
}
|
@ -44,7 +44,7 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
|
||||
* Name of the author
|
||||
*/
|
||||
private String author;
|
||||
private FeedImage image;
|
||||
private String imageUrl;
|
||||
private List<FeedItem> items;
|
||||
|
||||
/**
|
||||
@ -96,7 +96,7 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
|
||||
* This constructor is used for restoring a feed from the database.
|
||||
*/
|
||||
public Feed(long id, String lastUpdate, String title, String customTitle, String link, String description, String paymentLink,
|
||||
String author, String language, String type, String feedIdentifier, FeedImage image, String fileUrl,
|
||||
String author, String language, String type, String feedIdentifier, String imageUrl, String fileUrl,
|
||||
String downloadUrl, boolean downloaded, FlattrStatus status, boolean paged, String nextPageLink,
|
||||
String filter, boolean lastUpdateFailed) {
|
||||
super(fileUrl, downloadUrl, downloaded);
|
||||
@ -111,7 +111,7 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
|
||||
this.language = language;
|
||||
this.type = type;
|
||||
this.feedIdentifier = feedIdentifier;
|
||||
this.image = image;
|
||||
this.imageUrl = imageUrl;
|
||||
this.flattrStatus = status;
|
||||
this.paged = paged;
|
||||
this.nextPageLink = nextPageLink;
|
||||
@ -128,9 +128,9 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
|
||||
* This constructor is used for test purposes and uses a default flattr status object.
|
||||
*/
|
||||
public Feed(long id, String lastUpdate, String title, String link, String description, String paymentLink,
|
||||
String author, String language, String type, String feedIdentifier, FeedImage image, String fileUrl,
|
||||
String author, String language, String type, String feedIdentifier, String imageUrl, String fileUrl,
|
||||
String downloadUrl, boolean downloaded) {
|
||||
this(id, lastUpdate, title, null, link, description, paymentLink, author, language, type, feedIdentifier, image,
|
||||
this(id, lastUpdate, title, null, link, description, paymentLink, author, language, type, feedIdentifier, imageUrl,
|
||||
fileUrl, downloadUrl, downloaded, new FlattrStatus(), false, null, null, false);
|
||||
}
|
||||
|
||||
@ -191,6 +191,7 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
|
||||
int indexNextPageLink = cursor.getColumnIndex(PodDBAdapter.KEY_NEXT_PAGE_LINK);
|
||||
int indexHide = cursor.getColumnIndex(PodDBAdapter.KEY_HIDE);
|
||||
int indexLastUpdateFailed = cursor.getColumnIndex(PodDBAdapter.KEY_LAST_UPDATE_FAILED);
|
||||
int indexImageUrl = cursor.getColumnIndex(PodDBAdapter.KEY_IMAGE_URL);
|
||||
|
||||
Feed feed = new Feed(
|
||||
cursor.getLong(indexId),
|
||||
@ -204,7 +205,7 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
|
||||
cursor.getString(indexLanguage),
|
||||
cursor.getString(indexType),
|
||||
cursor.getString(indexFeedIdentifier),
|
||||
null,
|
||||
cursor.getString(indexImageUrl),
|
||||
cursor.getString(indexFileUrl),
|
||||
cursor.getString(indexDownloadUrl),
|
||||
cursor.getInt(indexDownloaded) > 0,
|
||||
@ -266,8 +267,8 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
|
||||
public void updateFromOther(Feed other) {
|
||||
// don't update feed's download_url, we do that manually if redirected
|
||||
// see AntennapodHttpClient
|
||||
if (other.image != null) {
|
||||
this.image = other.image;
|
||||
if (other.imageUrl != null) {
|
||||
this.imageUrl = other.imageUrl;
|
||||
}
|
||||
if (other.feedTitle != null) {
|
||||
feedTitle = other.feedTitle;
|
||||
@ -305,8 +306,8 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
|
||||
if (super.compareWithOther(other)) {
|
||||
return true;
|
||||
}
|
||||
if (other.image != null) {
|
||||
if (image == null || !TextUtils.equals(image.download_url, other.image.download_url)) {
|
||||
if (other.imageUrl != null) {
|
||||
if (imageUrl == null || !TextUtils.equals(imageUrl, other.imageUrl)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -411,12 +412,12 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public FeedImage getImage() {
|
||||
return image;
|
||||
public String getImageUrl() {
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
public void setImage(FeedImage image) {
|
||||
this.image = image;
|
||||
public void setImageUrl(String imageUrl) {
|
||||
this.imageUrl = imageUrl;
|
||||
}
|
||||
|
||||
public List<FeedItem> getItems() {
|
||||
@ -505,11 +506,7 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
|
||||
|
||||
@Override
|
||||
public String getImageLocation() {
|
||||
if (image != null) {
|
||||
return image.getImageLocation();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
public int getPageNr() {
|
||||
|
@ -1,92 +0,0 @@
|
||||
package de.danoeh.antennapod.core.feed;
|
||||
|
||||
import android.database.Cursor;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import de.danoeh.antennapod.core.asynctask.ImageResource;
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
|
||||
|
||||
public class FeedImage extends FeedFile implements ImageResource {
|
||||
public static final int FEEDFILETYPE_FEEDIMAGE = 1;
|
||||
|
||||
private String title;
|
||||
private FeedComponent owner;
|
||||
|
||||
public FeedImage(FeedComponent owner, String download_url, String title) {
|
||||
super(null, download_url, false);
|
||||
this.download_url = download_url;
|
||||
this.title = title;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public FeedImage(long id, String title, String file_url,
|
||||
String download_url, boolean downloaded) {
|
||||
super(file_url, download_url, downloaded);
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public FeedImage() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static FeedImage fromCursor(Cursor cursor) {
|
||||
int indexId = cursor.getColumnIndex(PodDBAdapter.KEY_ID);
|
||||
int indexTitle = cursor.getColumnIndex(PodDBAdapter.KEY_TITLE);
|
||||
int indexFileUrl = cursor.getColumnIndex(PodDBAdapter.KEY_FILE_URL);
|
||||
int indexDownloadUrl = cursor.getColumnIndex(PodDBAdapter.KEY_DOWNLOAD_URL);
|
||||
int indexDownloaded = cursor.getColumnIndex(PodDBAdapter.KEY_DOWNLOADED);
|
||||
|
||||
return new FeedImage(
|
||||
cursor.getLong(indexId),
|
||||
cursor.getString(indexTitle),
|
||||
cursor.getString(indexFileUrl),
|
||||
cursor.getString(indexDownloadUrl),
|
||||
cursor.getInt(indexDownloaded) > 0
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getHumanReadableIdentifier() {
|
||||
if (owner != null && owner.getHumanReadableIdentifier() != null) {
|
||||
return owner.getHumanReadableIdentifier();
|
||||
} else {
|
||||
return download_url;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTypeAsInt() {
|
||||
return FEEDFILETYPE_FEEDIMAGE;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public FeedComponent getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(FeedComponent owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImageLocation() {
|
||||
if (file_url != null && downloaded) {
|
||||
return new File(file_url).getAbsolutePath();
|
||||
} else if(download_url != null) {
|
||||
return download_url;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import android.database.Cursor;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import de.danoeh.antennapod.core.asynctask.ImageResource;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
@ -14,7 +15,6 @@ import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import de.danoeh.antennapod.core.asynctask.ImageResource;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
import de.danoeh.antennapod.core.util.ShownotesProvider;
|
||||
@ -75,7 +75,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
|
||||
* in the database. The 'hasChapters' attribute should be used to check if this item has any chapters.
|
||||
* */
|
||||
private List<Chapter> chapters;
|
||||
private FeedImage image;
|
||||
private String imageUrl;
|
||||
|
||||
/*
|
||||
* 0: auto download disabled
|
||||
@ -100,7 +100,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
|
||||
* This constructor is used by DBReader.
|
||||
* */
|
||||
public FeedItem(long id, String title, String link, Date pubDate, String paymentLink, long feedId,
|
||||
FlattrStatus flattrStatus, boolean hasChapters, FeedImage image, int state,
|
||||
FlattrStatus flattrStatus, boolean hasChapters, String imageUrl, int state,
|
||||
String itemIdentifier, long autoDownload) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
@ -110,7 +110,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
|
||||
this.feedId = feedId;
|
||||
this.flattrStatus = flattrStatus;
|
||||
this.hasChapters = hasChapters;
|
||||
this.image = image;
|
||||
this.imageUrl = imageUrl;
|
||||
this.state = state;
|
||||
this.itemIdentifier = itemIdentifier;
|
||||
this.autoDownload = autoDownload;
|
||||
@ -158,6 +158,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
|
||||
int indexRead = cursor.getColumnIndex(PodDBAdapter.KEY_READ);
|
||||
int indexItemIdentifier = cursor.getColumnIndex(PodDBAdapter.KEY_ITEM_IDENTIFIER);
|
||||
int indexAutoDownload = cursor.getColumnIndex(PodDBAdapter.KEY_AUTO_DOWNLOAD);
|
||||
int indexImageUrl = cursor.getColumnIndex(PodDBAdapter.KEY_IMAGE_URL);
|
||||
|
||||
long id = cursor.getInt(indexId);
|
||||
String title = cursor.getString(indexTitle);
|
||||
@ -170,15 +171,16 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
|
||||
int state = cursor.getInt(indexRead);
|
||||
String itemIdentifier = cursor.getString(indexItemIdentifier);
|
||||
long autoDownload = cursor.getLong(indexAutoDownload);
|
||||
String imageUrl = cursor.getString(indexImageUrl);
|
||||
|
||||
return new FeedItem(id, title, link, pubDate, paymentLink, feedId, flattrStatus,
|
||||
hasChapters, null, state, itemIdentifier, autoDownload);
|
||||
hasChapters, imageUrl, state, itemIdentifier, autoDownload);
|
||||
}
|
||||
|
||||
public void updateFromOther(FeedItem other) {
|
||||
super.updateFromOther(other);
|
||||
if (other.image != null) {
|
||||
this.image = other.image;
|
||||
if (other.imageUrl != null) {
|
||||
this.imageUrl = other.imageUrl;
|
||||
}
|
||||
if (other.title != null) {
|
||||
title = other.title;
|
||||
@ -212,9 +214,6 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
|
||||
chapters = other.chapters;
|
||||
}
|
||||
}
|
||||
if (image == null) {
|
||||
image = other.image;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -389,8 +388,8 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
|
||||
public String getImageLocation() {
|
||||
if(media != null && media.hasEmbeddedPicture()) {
|
||||
return media.getImageLocation();
|
||||
} else if (image != null) {
|
||||
return image.getImageLocation();
|
||||
} else if (imageUrl != null) {
|
||||
return imageUrl;
|
||||
} else if (feed != null) {
|
||||
return feed.getImageLocation();
|
||||
} else {
|
||||
@ -426,29 +425,12 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
|
||||
* Returns the image of this item or the image of the feed if this item does
|
||||
* not have its own image.
|
||||
*/
|
||||
public FeedImage getImage() {
|
||||
return (hasItemImage()) ? image : feed.getImage();
|
||||
public String getImageUrl() {
|
||||
return (imageUrl != null) ? imageUrl : feed.getImageUrl();
|
||||
}
|
||||
|
||||
public void setImage(FeedImage image) {
|
||||
this.image = image;
|
||||
if (image != null) {
|
||||
image.setOwner(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this FeedItem has its own image, false otherwise.
|
||||
*/
|
||||
public boolean hasItemImage() {
|
||||
return image != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this FeedItem has its own image and the image has been downloaded.
|
||||
*/
|
||||
public boolean hasItemImageDownloaded() {
|
||||
return image != null && image.isDownloaded();
|
||||
public void setImageUrl(String imageUrl) {
|
||||
this.imageUrl = imageUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -554,15 +554,9 @@ public class FeedMedia extends FeedFile implements Playable {
|
||||
public Callable<String> loadShownotes() {
|
||||
return () -> {
|
||||
if (item == null) {
|
||||
item = DBReader.getFeedItem(
|
||||
itemID);
|
||||
item = DBReader.getFeedItem(itemID);
|
||||
}
|
||||
if (item.getContentEncoded() == null || item.getDescription() == null) {
|
||||
DBReader.loadExtraInformationOfFeedItem(
|
||||
item);
|
||||
|
||||
}
|
||||
return (item.getContentEncoded() != null) ? item.getContentEncoded() : item.getDescription();
|
||||
return item.loadShownotes().call();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,21 @@
|
||||
package de.danoeh.antennapod.core.preferences;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.IntRange;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import de.danoeh.antennapod.core.R;
|
||||
import de.danoeh.antennapod.core.service.download.ProxyConfig;
|
||||
import de.danoeh.antennapod.core.storage.APCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
@ -21,19 +24,9 @@ import java.io.IOException;
|
||||
import java.net.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import de.danoeh.antennapod.core.R;
|
||||
import de.danoeh.antennapod.core.receiver.FeedUpdateReceiver;
|
||||
import de.danoeh.antennapod.core.service.download.ProxyConfig;
|
||||
import de.danoeh.antennapod.core.storage.APCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
|
||||
/**
|
||||
* Provides access to preferences set by the user in the settings screen. A
|
||||
* private instance of this class must first be instantiated via
|
||||
@ -168,6 +161,8 @@ public class UserPreferences {
|
||||
int theme = getTheme();
|
||||
if (theme == R.style.Theme_AntennaPod_Dark) {
|
||||
return R.style.Theme_AntennaPod_Dark_NoTitle;
|
||||
} else if (theme == R.style.Theme_AntennaPod_TrueBlack) {
|
||||
return R.style.Theme_AntennaPod_TrueBlack_NoTitle;
|
||||
} else {
|
||||
return R.style.Theme_AntennaPod_Light_NoTitle;
|
||||
}
|
||||
@ -604,6 +599,8 @@ public class UserPreferences {
|
||||
return R.style.Theme_AntennaPod_Light;
|
||||
case 1:
|
||||
return R.style.Theme_AntennaPod_Dark;
|
||||
case 2:
|
||||
return R.style.Theme_AntennaPod_TrueBlack;
|
||||
default:
|
||||
return R.style.Theme_AntennaPod_Light;
|
||||
}
|
||||
@ -781,60 +778,17 @@ public class UserPreferences {
|
||||
int[] timeOfDay = getUpdateTimeOfDay();
|
||||
Log.d(TAG, "timeOfDay: " + Arrays.toString(timeOfDay));
|
||||
if (timeOfDay.length == 2) {
|
||||
restartUpdateTimeOfDayAlarm(timeOfDay[0], timeOfDay[1]);
|
||||
AutoUpdateManager.restartUpdateTimeOfDayAlarm(context, timeOfDay[0], timeOfDay[1]);
|
||||
} else {
|
||||
long milliseconds = getUpdateInterval();
|
||||
long startTrigger = milliseconds;
|
||||
if (now) {
|
||||
startTrigger = TimeUnit.SECONDS.toMillis(10);
|
||||
}
|
||||
restartUpdateIntervalAlarm(startTrigger, milliseconds);
|
||||
AutoUpdateManager.restartUpdateIntervalAlarm(context, startTrigger, milliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the interval in which the feeds are refreshed automatically
|
||||
*/
|
||||
private static void restartUpdateIntervalAlarm(long triggerAtMillis, long intervalMillis) {
|
||||
Log.d(TAG, "Restarting update alarm.");
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
Intent intent = new Intent(context, FeedUpdateReceiver.class);
|
||||
PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
|
||||
alarmManager.cancel(updateIntent);
|
||||
if (intervalMillis > 0) {
|
||||
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime() + triggerAtMillis,
|
||||
updateIntent);
|
||||
Log.d(TAG, "Changed alarm to new interval " + TimeUnit.MILLISECONDS.toHours(intervalMillis) + " h");
|
||||
} else {
|
||||
Log.d(TAG, "Automatic update was deactivated");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets time of day the feeds are refreshed automatically
|
||||
*/
|
||||
private static void restartUpdateTimeOfDayAlarm(int hoursOfDay, int minute) {
|
||||
Log.d(TAG, "Restarting update alarm.");
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0,
|
||||
new Intent(context, FeedUpdateReceiver.class), 0);
|
||||
alarmManager.cancel(updateIntent);
|
||||
|
||||
Calendar now = Calendar.getInstance();
|
||||
Calendar alarm = (Calendar)now.clone();
|
||||
alarm.set(Calendar.HOUR_OF_DAY, hoursOfDay);
|
||||
alarm.set(Calendar.MINUTE, minute);
|
||||
if (alarm.before(now) || alarm.equals(now)) {
|
||||
alarm.add(Calendar.DATE, 1);
|
||||
}
|
||||
Log.d(TAG, "Alarm set for: " + alarm.toString() + " : " + alarm.getTimeInMillis());
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP,
|
||||
alarm.getTimeInMillis(),
|
||||
updateIntent);
|
||||
Log.d(TAG, "Changed alarm to new time of day " + hoursOfDay + ":" + minute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads episode cache size as it is saved in the episode_cache_size_values array.
|
||||
*/
|
||||
|
@ -7,8 +7,7 @@ import android.util.Log;
|
||||
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import de.danoeh.antennapod.core.util.FeedUpdateUtils;
|
||||
|
||||
/**
|
||||
* Refreshes all feeds when it receives an intent
|
||||
@ -21,11 +20,7 @@ public class FeedUpdateReceiver extends BroadcastReceiver {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.d(TAG, "Received intent");
|
||||
ClientConfig.initialize(context);
|
||||
if (NetworkUtils.networkAvailable() && NetworkUtils.isDownloadAllowed()) {
|
||||
DBTasks.refreshAllFeeds(context, null);
|
||||
} else {
|
||||
Log.d(TAG, "Blocking automatic update: no wifi available / no mobile updates allowed");
|
||||
}
|
||||
FeedUpdateUtils.startAutoUpdate(context, null);
|
||||
UserPreferences.restartUpdateAlarm(false);
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package de.danoeh.antennapod.core.receiver;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
@ -29,7 +30,7 @@ public class MediaButtonReceiver extends BroadcastReceiver {
|
||||
Intent serviceIntent = new Intent(context, PlaybackService.class);
|
||||
serviceIntent.putExtra(EXTRA_KEYCODE, event.getKeyCode());
|
||||
serviceIntent.putExtra(EXTRA_SOURCE, event.getSource());
|
||||
context.startService(serviceIntent);
|
||||
ContextCompat.startForegroundService(context, serviceIntent);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,17 +1,15 @@
|
||||
package de.danoeh.antennapod.receiver;
|
||||
package de.danoeh.antennapod.core.receiver;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.core.service.PlayerWidgetJobService;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.service.PlayerWidgetService;
|
||||
|
||||
public class PlayerWidget extends AppWidgetProvider {
|
||||
private static final String TAG = "PlayerWidget";
|
||||
@ -22,17 +20,7 @@ public class PlayerWidget extends AppWidgetProvider {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.d(TAG, "onReceive");
|
||||
super.onReceive(context, intent);
|
||||
// don't do anything if we're not enabled
|
||||
if (!isEnabled(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// these come from the PlaybackService when things should get updated
|
||||
if (TextUtils.equals(intent.getAction(), PlaybackService.FORCE_WIDGET_UPDATE)) {
|
||||
startUpdate(context);
|
||||
} else if (TextUtils.equals(intent.getAction(), PlaybackService.STOP_WIDGET_UPDATE)) {
|
||||
stopUpdate(context);
|
||||
}
|
||||
PlayerWidgetJobService.updateWidget(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -40,14 +28,13 @@ public class PlayerWidget extends AppWidgetProvider {
|
||||
super.onEnabled(context);
|
||||
Log.d(TAG, "Widget enabled");
|
||||
setEnabled(context, true);
|
||||
startUpdate(context);
|
||||
PlayerWidgetJobService.updateWidget(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
|
||||
int[] appWidgetIds) {
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||
Log.d(TAG, "onUpdate() called with: " + "context = [" + context + "], appWidgetManager = [" + appWidgetManager + "], appWidgetIds = [" + Arrays.toString(appWidgetIds) + "]");
|
||||
startUpdate(context);
|
||||
PlayerWidgetJobService.updateWidget(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -55,20 +42,9 @@ public class PlayerWidget extends AppWidgetProvider {
|
||||
super.onDisabled(context);
|
||||
Log.d(TAG, "Widget disabled");
|
||||
setEnabled(context, false);
|
||||
stopUpdate(context);
|
||||
}
|
||||
|
||||
private void startUpdate(Context context) {
|
||||
Log.d(TAG, "startUpdate() called with: " + "context = [" + context + "]");
|
||||
context.startService(new Intent(context, PlayerWidgetService.class));
|
||||
}
|
||||
|
||||
private void stopUpdate(Context context) {
|
||||
Log.d(TAG, "stopUpdate() called with: " + "context = [" + context + "]");
|
||||
context.stopService(new Intent(context, PlayerWidgetService.class));
|
||||
}
|
||||
|
||||
private boolean isEnabled(Context context) {
|
||||
public static boolean isEnabled(Context context) {
|
||||
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||
return prefs.getBoolean(KEY_ENABLED, false);
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package de.danoeh.antennapod.core.service;
|
||||
|
||||
import android.app.job.JobParameters;
|
||||
import android.app.job.JobService;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.util.FeedUpdateUtils;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public class FeedUpdateJobService extends JobService {
|
||||
private static final String TAG = "FeedUpdateJobService";
|
||||
|
||||
@Override
|
||||
public boolean onStartJob(JobParameters params) {
|
||||
Log.d(TAG, "Job started");
|
||||
ClientConfig.initialize(getApplicationContext());
|
||||
|
||||
FeedUpdateUtils.startAutoUpdate(getApplicationContext(), () -> {
|
||||
UserPreferences.restartUpdateAlarm(false);
|
||||
jobFinished(params, false); // needsReschedule = false
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onStopJob(JobParameters params) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -3,10 +3,10 @@ package de.danoeh.antennapod.core.service;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.JobIntentService;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
@ -15,6 +15,7 @@ import android.util.Pair;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.R;
|
||||
@ -37,12 +38,13 @@ import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
|
||||
|
||||
/**
|
||||
* Synchronizes local subscriptions with gpodder.net service. The service should be started with ACTION_SYNC as an action argument.
|
||||
* This class also provides static methods for starting the GpodnetSyncService.
|
||||
*/
|
||||
public class GpodnetSyncService extends Service {
|
||||
public class GpodnetSyncService extends JobIntentService {
|
||||
private static final String TAG = "GpodnetSyncService";
|
||||
|
||||
private static final long WAIT_INTERVAL = 5000L;
|
||||
@ -55,12 +57,17 @@ public class GpodnetSyncService extends Service {
|
||||
|
||||
private GpodnetService service;
|
||||
|
||||
private boolean syncSubscriptions = false;
|
||||
private boolean syncActions = false;
|
||||
private static final AtomicInteger syncActionCount = new AtomicInteger(0);
|
||||
private static boolean syncSubscriptions = false;
|
||||
private static boolean syncActions = false;
|
||||
|
||||
private static void enqueueWork(Context context, Intent intent) {
|
||||
enqueueWork(context, GpodnetSyncService.class, 0, intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
final String action = (intent != null) ? intent.getStringExtra(ARG_ACTION) : null;
|
||||
protected void onHandleWork(@NonNull Intent intent) {
|
||||
final String action = intent.getStringExtra(ARG_ACTION);
|
||||
if (action != null) {
|
||||
switch(action) {
|
||||
case ACTION_SYNC:
|
||||
@ -78,24 +85,20 @@ public class GpodnetSyncService extends Service {
|
||||
}
|
||||
if(syncSubscriptions || syncActions) {
|
||||
Log.d(TAG, String.format("Waiting %d milliseconds before uploading changes", WAIT_INTERVAL));
|
||||
syncWaiterThread.restart();
|
||||
int syncActionId = syncActionCount.incrementAndGet();
|
||||
try {
|
||||
Thread.sleep(WAIT_INTERVAL);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (syncActionId == syncActionCount.get()) {
|
||||
// onHandleWork was not called again in the meantime
|
||||
sync();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Received invalid intent: action argument is null");
|
||||
}
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
Log.d(TAG, "onDestroy");
|
||||
syncWaiterThread.interrupt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private synchronized GpodnetService tryLogin() throws GpodnetServiceException {
|
||||
@ -109,6 +112,7 @@ public class GpodnetSyncService extends Service {
|
||||
|
||||
private synchronized void sync() {
|
||||
if (!GpodnetPreferences.loggedIn() || !NetworkUtils.networkAvailable()) {
|
||||
stopForeground(true);
|
||||
stopSelf();
|
||||
return;
|
||||
}
|
||||
@ -125,7 +129,6 @@ public class GpodnetSyncService extends Service {
|
||||
}
|
||||
syncActions = false;
|
||||
}
|
||||
stopSelf();
|
||||
}
|
||||
|
||||
private synchronized void syncSubscriptionChanges() {
|
||||
@ -319,7 +322,7 @@ public class GpodnetSyncService extends Service {
|
||||
}
|
||||
|
||||
PendingIntent activityIntent = ClientConfig.gpodnetCallbacks.getGpodnetSyncServiceErrorNotificationPendingIntent(this);
|
||||
Notification notification = new NotificationCompat.Builder(this)
|
||||
Notification notification = new NotificationCompat.Builder(this, NotificationUtils.CHANNEL_ID_ERROR)
|
||||
.setContentTitle(title)
|
||||
.setContentText(description)
|
||||
.setContentIntent(activityIntent)
|
||||
@ -331,69 +334,11 @@ public class GpodnetSyncService extends Service {
|
||||
nm.notify(id, notification);
|
||||
}
|
||||
|
||||
private final WaiterThread syncWaiterThread = new WaiterThread(WAIT_INTERVAL) {
|
||||
@Override
|
||||
public void onWaitCompleted() {
|
||||
sync();
|
||||
}
|
||||
};
|
||||
|
||||
private abstract class WaiterThread {
|
||||
private final long waitInterval;
|
||||
private Thread thread;
|
||||
|
||||
private WaiterThread(long waitInterval) {
|
||||
this.waitInterval = waitInterval;
|
||||
reinit();
|
||||
}
|
||||
|
||||
public abstract void onWaitCompleted();
|
||||
|
||||
public void exec() {
|
||||
if (!thread.isAlive()) {
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
|
||||
private void reinit() {
|
||||
if (thread != null && thread.isAlive()) {
|
||||
Log.d(TAG, "Interrupting waiter thread");
|
||||
thread.interrupt();
|
||||
}
|
||||
thread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(waitInterval);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (!isInterrupted()) {
|
||||
synchronized (this) {
|
||||
onWaitCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
reinit();
|
||||
exec();
|
||||
}
|
||||
|
||||
public void interrupt() {
|
||||
if (thread != null && thread.isAlive()) {
|
||||
thread.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendSyncIntent(Context context) {
|
||||
if (GpodnetPreferences.loggedIn()) {
|
||||
Intent intent = new Intent(context, GpodnetSyncService.class);
|
||||
intent.putExtra(ARG_ACTION, ACTION_SYNC);
|
||||
context.startService(intent);
|
||||
enqueueWork(context, intent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -401,7 +346,7 @@ public class GpodnetSyncService extends Service {
|
||||
if (GpodnetPreferences.loggedIn()) {
|
||||
Intent intent = new Intent(context, GpodnetSyncService.class);
|
||||
intent.putExtra(ARG_ACTION, ACTION_SYNC_SUBSCRIPTIONS);
|
||||
context.startService(intent);
|
||||
enqueueWork(context, intent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -409,7 +354,7 @@ public class GpodnetSyncService extends Service {
|
||||
if (GpodnetPreferences.loggedIn()) {
|
||||
Intent intent = new Intent(context, GpodnetSyncService.class);
|
||||
intent.putExtra(ARG_ACTION, ACTION_SYNC_ACTIONS);
|
||||
context.startService(intent);
|
||||
enqueueWork(context, intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,176 @@
|
||||
package de.danoeh.antennapod.core.service;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.JobIntentService;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
import de.danoeh.antennapod.core.R;
|
||||
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
import de.danoeh.antennapod.core.receiver.PlayerWidget;
|
||||
|
||||
/**
|
||||
* Updates the state of the player widget
|
||||
*/
|
||||
public class PlayerWidgetJobService extends JobIntentService {
|
||||
private static final String TAG = "PlayerWidgetJobService";
|
||||
|
||||
private PlaybackService playbackService;
|
||||
private final Object waitForService = new Object();
|
||||
|
||||
public static void updateWidget(Context context) {
|
||||
enqueueWork(context, PlayerWidgetJobService.class, 0, new Intent(context, PlayerWidgetJobService.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleWork(@NonNull Intent intent) {
|
||||
if (!PlayerWidget.isEnabled(getApplicationContext())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (PlaybackService.isRunning && playbackService == null) {
|
||||
synchronized (waitForService) {
|
||||
bindService(new Intent(this, PlaybackService.class), mConnection, 0);
|
||||
while (playbackService == null) {
|
||||
try {
|
||||
waitForService.wait();
|
||||
} catch (InterruptedException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateViews();
|
||||
|
||||
if (playbackService != null) {
|
||||
try {
|
||||
unbindService(mConnection);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.w(TAG, "IllegalArgumentException when trying to unbind service");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateViews() {
|
||||
|
||||
ComponentName playerWidget = new ComponentName(this, PlayerWidget.class);
|
||||
AppWidgetManager manager = AppWidgetManager.getInstance(this);
|
||||
RemoteViews views = new RemoteViews(getPackageName(), R.layout.player_widget);
|
||||
PendingIntent startMediaplayer = PendingIntent.getActivity(this, 0,
|
||||
PlaybackService.getPlayerActivityIntent(this), 0);
|
||||
|
||||
final PendingIntent startAppPending = PendingIntent.getActivity(this, 0,
|
||||
PlaybackService.getPlayerActivityIntent(this),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
boolean nothingPlaying = false;
|
||||
Playable media;
|
||||
PlayerStatus status;
|
||||
if (playbackService != null) {
|
||||
media = playbackService.getPlayable();
|
||||
status = playbackService.getStatus();
|
||||
} else {
|
||||
media = Playable.PlayableUtils.createInstanceFromPreferences(getApplicationContext());
|
||||
status = PlayerStatus.STOPPED;
|
||||
}
|
||||
|
||||
if (media != null) {
|
||||
views.setOnClickPendingIntent(R.id.layout_left, startMediaplayer);
|
||||
|
||||
views.setTextViewText(R.id.txtvTitle, media.getEpisodeTitle());
|
||||
|
||||
String progressString;
|
||||
if (playbackService != null) {
|
||||
progressString = getProgressString(playbackService.getCurrentPosition(), playbackService.getDuration());
|
||||
} else {
|
||||
progressString = getProgressString(media.getPosition(), media.getDuration());
|
||||
}
|
||||
|
||||
if (progressString != null) {
|
||||
views.setViewVisibility(R.id.txtvProgress, View.VISIBLE);
|
||||
views.setTextViewText(R.id.txtvProgress, progressString);
|
||||
}
|
||||
|
||||
if (status == PlayerStatus.PLAYING) {
|
||||
views.setImageViewResource(R.id.butPlay, R.drawable.ic_pause_white_24dp);
|
||||
if (Build.VERSION.SDK_INT >= 15) {
|
||||
views.setContentDescription(R.id.butPlay, getString(R.string.pause_label));
|
||||
}
|
||||
} else {
|
||||
views.setImageViewResource(R.id.butPlay, R.drawable.ic_play_arrow_white_24dp);
|
||||
if (Build.VERSION.SDK_INT >= 15) {
|
||||
views.setContentDescription(R.id.butPlay, getString(R.string.play_label));
|
||||
}
|
||||
}
|
||||
views.setOnClickPendingIntent(R.id.butPlay, createMediaButtonIntent());
|
||||
} else {
|
||||
nothingPlaying = true;
|
||||
}
|
||||
|
||||
if (nothingPlaying) {
|
||||
// start the app if they click anything
|
||||
views.setOnClickPendingIntent(R.id.layout_left, startAppPending);
|
||||
views.setOnClickPendingIntent(R.id.butPlay, startAppPending);
|
||||
views.setViewVisibility(R.id.txtvProgress, View.INVISIBLE);
|
||||
views.setTextViewText(R.id.txtvTitle,
|
||||
this.getString(R.string.no_media_playing_label));
|
||||
views.setImageViewResource(R.id.butPlay, R.drawable.ic_play_arrow_white_24dp);
|
||||
}
|
||||
|
||||
manager.updateAppWidget(playerWidget, views);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an intent which fakes a mediabutton press
|
||||
*/
|
||||
private PendingIntent createMediaButtonIntent() {
|
||||
KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
|
||||
Intent startingIntent = new Intent(getBaseContext(), MediaButtonReceiver.class);
|
||||
startingIntent.setAction(MediaButtonReceiver.NOTIFY_BUTTON_RECEIVER);
|
||||
startingIntent.putExtra(Intent.EXTRA_KEY_EVENT, event);
|
||||
|
||||
return PendingIntent.getBroadcast(this, 0, startingIntent, 0);
|
||||
}
|
||||
|
||||
private String getProgressString(int position, int duration) {
|
||||
if (position > 0 && duration > 0) {
|
||||
return Converter.getDurationStringLong(position) + " / "
|
||||
+ Converter.getDurationStringLong(duration);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private final ServiceConnection mConnection = new ServiceConnection() {
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
Log.d(TAG, "Connection to service established");
|
||||
if (service instanceof PlaybackService.LocalBinder) {
|
||||
synchronized (waitForService) {
|
||||
playbackService = ((PlaybackService.LocalBinder) service).getService();
|
||||
waitForService.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
playbackService = null;
|
||||
Log.d(TAG, "Disconnected from service");
|
||||
}
|
||||
|
||||
};
|
||||
}
|
@ -7,8 +7,6 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
@ -23,6 +21,7 @@ import android.util.Pair;
|
||||
import android.webkit.URLUtil;
|
||||
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
@ -57,7 +56,6 @@ import de.danoeh.antennapod.core.R;
|
||||
import de.danoeh.antennapod.core.event.DownloadEvent;
|
||||
import de.danoeh.antennapod.core.event.FeedItemEvent;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.feed.FeedPreferences;
|
||||
@ -297,6 +295,7 @@ public class DownloadService extends Service {
|
||||
|
||||
setupNotificationBuilders();
|
||||
requester = DownloadRequester.getInstance();
|
||||
startForeground(NOTIFICATION_ID, updateNotifications());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -342,7 +341,7 @@ public class DownloadService extends Service {
|
||||
}
|
||||
|
||||
private void setupNotificationBuilders() {
|
||||
notificationCompatBuilder = new NotificationCompat.Builder(this)
|
||||
notificationCompatBuilder = new NotificationCompat.Builder(this, NotificationUtils.CHANNEL_ID_DOWNLOADING)
|
||||
.setOngoing(true)
|
||||
.setContentIntent(ClientConfig.downloadServiceCallbacks.getNotificationContentIntent(this))
|
||||
.setSmallIcon(R.drawable.stat_notify_sync);
|
||||
@ -355,7 +354,7 @@ public class DownloadService extends Service {
|
||||
|
||||
/**
|
||||
* Updates the contents of the service's notifications. Should be called
|
||||
* before setupNotificationBuilders.
|
||||
* after setupNotificationBuilders.
|
||||
*/
|
||||
private Notification updateNotifications() {
|
||||
if (notificationCompatBuilder == null) {
|
||||
@ -492,9 +491,7 @@ public class DownloadService extends Service {
|
||||
if (status.isSuccessful()) {
|
||||
successfulDownloads++;
|
||||
} else if (!status.isCancelled()) {
|
||||
if (status.getFeedfileType() != FeedImage.FEEDFILETYPE_FEEDIMAGE) {
|
||||
createReport = true;
|
||||
}
|
||||
createReport = true;
|
||||
failedDownloads++;
|
||||
}
|
||||
}
|
||||
@ -502,7 +499,7 @@ public class DownloadService extends Service {
|
||||
if (createReport) {
|
||||
Log.d(TAG, "Creating report");
|
||||
// create notification object
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NotificationUtils.CHANNEL_ID_ERROR)
|
||||
.setTicker(getString(R.string.download_report_title))
|
||||
.setContentTitle(getString(R.string.download_report_content_title))
|
||||
.setContentText(
|
||||
@ -554,7 +551,7 @@ public class DownloadService extends Service {
|
||||
final String resourceTitle = (downloadRequest.getTitle() != null) ?
|
||||
downloadRequest.getTitle() : downloadRequest.getSource();
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(DownloadService.this);
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(DownloadService.this, NotificationUtils.CHANNEL_ID_USER_ACTION);
|
||||
builder.setTicker(getText(R.string.authentication_notification_title))
|
||||
.setContentTitle(getText(R.string.authentication_notification_title))
|
||||
.setContentText(getText(R.string.authentication_notification_msg))
|
||||
@ -691,10 +688,6 @@ public class DownloadService extends Service {
|
||||
|
||||
Log.d(TAG, "Bundling " + results.size() + " feeds");
|
||||
|
||||
for (Pair<DownloadRequest, FeedHandlerResult> result : results) {
|
||||
removeDuplicateImages(result.second.feed); // duplicate images have to removed because the DownloadRequester does not accept two downloads with the same download URL yet.
|
||||
}
|
||||
|
||||
// Save information of feed in DB
|
||||
if (dbUpdateFuture != null) {
|
||||
try {
|
||||
@ -1104,26 +1097,6 @@ public class DownloadService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the FeedItems of this feed have images that point to the same URL. If two FeedItems
|
||||
* have an image that points to the same URL, the reference of the second item is removed, so
|
||||
* that every image reference is unique.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static void removeDuplicateImages(Feed feed) {
|
||||
Set<String> known = new HashSet<>();
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
String url = item.hasItemImage() ? item.getImage().getDownload_url() : null;
|
||||
if (url != null) {
|
||||
if (known.contains(url)) {
|
||||
item.setImage(null);
|
||||
} else {
|
||||
known.add(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String compileNotificationString(List<Downloader> downloads) {
|
||||
List<String> lines = new ArrayList<>(downloads.size());
|
||||
for (Downloader downloader : downloads) {
|
||||
|
@ -20,7 +20,6 @@ import java.util.Date;
|
||||
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.R;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.util.DateUtils;
|
||||
import de.danoeh.antennapod.core.util.DownloadError;
|
||||
@ -50,13 +49,8 @@ public class HttpDownloader extends Downloader {
|
||||
|
||||
if (request.isDeleteOnFailure() && fileExists) {
|
||||
Log.w(TAG, "File already exists");
|
||||
if (request.getFeedfileType() != FeedImage.FEEDFILETYPE_FEEDIMAGE) {
|
||||
onFail(DownloadError.ERROR_FILE_EXISTS, null);
|
||||
return;
|
||||
} else {
|
||||
onSuccess();
|
||||
return;
|
||||
}
|
||||
onSuccess();
|
||||
return;
|
||||
}
|
||||
|
||||
OkHttpClient.Builder httpClientBuilder = AntennapodHttpClient.newBuilder();
|
||||
|
@ -609,6 +609,9 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
|
||||
public void shutdown() {
|
||||
executor.shutdown();
|
||||
if (mediaPlayer != null) {
|
||||
try {
|
||||
mediaPlayer.stop();
|
||||
} catch (Exception ignore) { }
|
||||
mediaPlayer.release();
|
||||
}
|
||||
releaseWifiLockIfNecessary();
|
||||
|
@ -30,12 +30,10 @@ import android.support.v4.media.MediaDescriptionCompat;
|
||||
import android.support.v4.media.MediaMetadataCompat;
|
||||
import android.support.v4.media.session.MediaSessionCompat;
|
||||
import android.support.v4.media.session.PlaybackStateCompat;
|
||||
import android.support.v4.view.InputDeviceCompat;
|
||||
import android.support.v7.app.NotificationCompat;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.widget.Toast;
|
||||
@ -49,6 +47,7 @@ import java.util.List;
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.R;
|
||||
import de.danoeh.antennapod.core.event.MessageEvent;
|
||||
import de.danoeh.antennapod.core.event.ServiceEvent;
|
||||
import de.danoeh.antennapod.core.feed.Chapter;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
@ -60,11 +59,13 @@ import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
|
||||
import de.danoeh.antennapod.core.preferences.SleepTimerPreferences;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
|
||||
import de.danoeh.antennapod.core.service.PlayerWidgetJobService;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.storage.FeedSearcher;
|
||||
import de.danoeh.antennapod.core.util.IntList;
|
||||
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
|
||||
import de.danoeh.antennapod.core.util.QueueAccess;
|
||||
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
|
||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
@ -74,8 +75,6 @@ import de.greenrobot.event.EventBus;
|
||||
* Controls the MediaPlayer that plays a FeedMedia-file
|
||||
*/
|
||||
public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
public static final String FORCE_WIDGET_UPDATE = "de.danoeh.antennapod.FORCE_WIDGET_UPDATE";
|
||||
public static final String STOP_WIDGET_UPDATE = "de.danoeh.antennapod.STOP_WIDGET_UPDATE";
|
||||
/**
|
||||
* Logging tag
|
||||
*/
|
||||
@ -313,6 +312,31 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
flavorHelper.initializeMediaPlayer(PlaybackService.this);
|
||||
|
||||
mediaSession.setActive(true);
|
||||
|
||||
NotificationCompat.Builder notificationBuilder = createBasicNotification();
|
||||
startForeground(NOTIFICATION_ID, notificationBuilder.build());
|
||||
EventBus.getDefault().post(new ServiceEvent(ServiceEvent.Action.SERVICE_STARTED));
|
||||
|
||||
|
||||
setupNotification(Playable.PlayableUtils.createInstanceFromPreferences(getApplicationContext()));
|
||||
}
|
||||
|
||||
private NotificationCompat.Builder createBasicNotification() {
|
||||
final int smallIcon = ClientConfig.playbackServiceCallbacks.getNotificationIconResource(getApplicationContext());
|
||||
|
||||
final PendingIntent pIntent = PendingIntent.getActivity(this, 0,
|
||||
PlaybackService.getPlayerActivityIntent(this),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
return new NotificationCompat.Builder(
|
||||
this, NotificationUtils.CHANNEL_ID_PLAYING)
|
||||
.setContentTitle(getString(R.string.app_name))
|
||||
.setContentText("Service is running") // Just in case the notification is not updated (should not occur)
|
||||
.setOngoing(false)
|
||||
.setContentIntent(pIntent)
|
||||
.setWhen(0) // we don't need the time
|
||||
.setSmallIcon(smallIcon)
|
||||
.setPriority(NotificationCompat.PRIORITY_MIN);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -447,8 +471,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
|
||||
if (keycode != -1) {
|
||||
Log.d(TAG, "Received media button event");
|
||||
handleKeycode(keycode, intent.getIntExtra(MediaButtonReceiver.EXTRA_SOURCE,
|
||||
InputDeviceCompat.SOURCE_CLASS_NONE));
|
||||
handleKeycode(keycode, true);
|
||||
} else if (!flavorHelper.castDisconnect(castDisconnect) && playable != null) {
|
||||
started = true;
|
||||
boolean stream = intent.getBooleanExtra(EXTRA_SHOULD_STREAM,
|
||||
@ -472,7 +495,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
* Handles media button events
|
||||
* return: keycode was handled
|
||||
*/
|
||||
private boolean handleKeycode(int keycode, int source) {
|
||||
private boolean handleKeycode(int keycode, boolean notificationButton) {
|
||||
Log.d(TAG, "Handling keycode: " + keycode);
|
||||
final PlaybackServiceMediaPlayer.PSMPInfo info = mediaPlayer.getPSMPInfo();
|
||||
final PlayerStatus status = info.playerStatus;
|
||||
@ -488,6 +511,8 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
} else if (status == PlayerStatus.INITIALIZED) {
|
||||
mediaPlayer.setStartWhenPrepared(true);
|
||||
mediaPlayer.prepare();
|
||||
} else if (mediaPlayer.getPlayable() == null) {
|
||||
startPlayingFromPreferences();
|
||||
}
|
||||
return true;
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY:
|
||||
@ -496,6 +521,8 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
} else if (status == PlayerStatus.INITIALIZED) {
|
||||
mediaPlayer.setStartWhenPrepared(true);
|
||||
mediaPlayer.prepare();
|
||||
} else if (mediaPlayer.getPlayable() == null) {
|
||||
startPlayingFromPreferences();
|
||||
}
|
||||
return true;
|
||||
case KeyEvent.KEYCODE_MEDIA_PAUSE:
|
||||
@ -505,7 +532,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
|
||||
return true;
|
||||
case KeyEvent.KEYCODE_MEDIA_NEXT:
|
||||
if (source == InputDevice.SOURCE_CLASS_NONE ||
|
||||
if (notificationButton ||
|
||||
UserPreferences.shouldHardwareButtonSkip()) {
|
||||
// assume the skip command comes from a notification or the lockscreen
|
||||
// a >| skip button should actually skip
|
||||
@ -549,6 +576,15 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void startPlayingFromPreferences() {
|
||||
Playable playable = Playable.PlayableUtils.createInstanceFromPreferences(getApplicationContext());
|
||||
if (playable != null) {
|
||||
mediaPlayer.playMediaObject(playable, false, true, true);
|
||||
started = true;
|
||||
PlaybackService.this.updateMediaSessionMetadata(playable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by a mediaplayer Activity as soon as it has prepared its
|
||||
* mediaplayer.
|
||||
@ -567,8 +603,10 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
}
|
||||
|
||||
public void notifyVideoSurfaceAbandoned() {
|
||||
stopForeground(!UserPreferences.isPersistNotify());
|
||||
mediaPlayer.pause(true, false);
|
||||
mediaPlayer.resetVideoSurface();
|
||||
setupNotification(getPlayable());
|
||||
stopForeground(!UserPreferences.isPersistNotify());
|
||||
}
|
||||
|
||||
private final PlaybackServiceTaskManager.PSTMCallback taskManagerCallback = new PlaybackServiceTaskManager.PSTMCallback() {
|
||||
@ -602,7 +640,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
|
||||
@Override
|
||||
public void onWidgetUpdaterTick() {
|
||||
updateWidget();
|
||||
PlayerWidgetJobService.updateWidget(getBaseContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -664,7 +702,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
Intent statusUpdate = new Intent(ACTION_PLAYER_STATUS_CHANGED);
|
||||
// statusUpdate.putExtra(EXTRA_NEW_PLAYER_STATUS, newInfo.playerStatus.ordinal());
|
||||
sendBroadcast(statusUpdate);
|
||||
updateWidget();
|
||||
PlayerWidgetJobService.updateWidget(getBaseContext());
|
||||
bluetoothNotifyChange(newInfo, AVRCP_ACTION_PLAYER_STATUS_CHANGED);
|
||||
bluetoothNotifyChange(newInfo, AVRCP_ACTION_META_CHANGED);
|
||||
}
|
||||
@ -807,7 +845,6 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
if (!isCasting) {
|
||||
stopForeground(true);
|
||||
}
|
||||
stopWidgetUpdater();
|
||||
}
|
||||
if (mediaType == null) {
|
||||
sendNotificationBroadcast(NOTIFICATION_TYPE_PLAYBACK_END, 0);
|
||||
@ -1171,10 +1208,10 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
* Prepares notification and starts the service in the foreground.
|
||||
*/
|
||||
private void setupNotification(final PlaybackServiceMediaPlayer.PSMPInfo info) {
|
||||
final PendingIntent pIntent = PendingIntent.getActivity(this, 0,
|
||||
PlaybackService.getPlayerActivityIntent(this),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
setupNotification(info.playable);
|
||||
}
|
||||
|
||||
private synchronized void setupNotification(final Playable playable) {
|
||||
if (notificationSetupThread != null) {
|
||||
notificationSetupThread.interrupt();
|
||||
}
|
||||
@ -1184,12 +1221,12 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(TAG, "Starting background work");
|
||||
if (info.playable != null) {
|
||||
if (playable != null) {
|
||||
int iconSize = getResources().getDimensionPixelSize(
|
||||
android.R.dimen.notification_large_icon_width);
|
||||
try {
|
||||
icon = Glide.with(PlaybackService.this)
|
||||
.load(info.playable.getImageLocation())
|
||||
.load(playable.getImageLocation())
|
||||
.asBitmap()
|
||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||
.centerCrop()
|
||||
@ -1208,24 +1245,18 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
return;
|
||||
}
|
||||
PlayerStatus playerStatus = mediaPlayer.getPlayerStatus();
|
||||
final int smallIcon = ClientConfig.playbackServiceCallbacks.getNotificationIconResource(getApplicationContext());
|
||||
|
||||
if (!Thread.currentThread().isInterrupted() && started && info.playable != null) {
|
||||
String contentText = info.playable.getEpisodeTitle();
|
||||
String contentTitle = info.playable.getFeedTitle();
|
||||
if (!Thread.currentThread().isInterrupted() && started && playable != null) {
|
||||
String contentText = playable.getEpisodeTitle();
|
||||
String contentTitle = playable.getFeedTitle();
|
||||
Notification notification;
|
||||
|
||||
// Builder is v7, even if some not overwritten methods return its parent's v4 interface
|
||||
NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(
|
||||
PlaybackService.this)
|
||||
.setContentTitle(contentTitle)
|
||||
NotificationCompat.Builder notificationBuilder = createBasicNotification();
|
||||
notificationBuilder.setContentTitle(contentTitle)
|
||||
.setContentText(contentText)
|
||||
.setOngoing(false)
|
||||
.setContentIntent(pIntent)
|
||||
.setLargeIcon(icon)
|
||||
.setSmallIcon(smallIcon)
|
||||
.setWhen(0) // we don't need the time
|
||||
.setPriority(UserPreferences.getNotifyPriority()); // set notification priority
|
||||
.setPriority(UserPreferences.getNotifyPriority())
|
||||
.setLargeIcon(icon); // set notification priority
|
||||
IntList compactActionList = new IntList();
|
||||
|
||||
int numActions = 0; // we start and 0 and then increment by 1 for each call to addAction
|
||||
@ -1293,7 +1324,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
|
||||
PendingIntent stopButtonPendingIntent = getPendingIntentForMediaAction(
|
||||
KeyEvent.KEYCODE_MEDIA_STOP, numActions);
|
||||
notificationBuilder.setStyle(new android.support.v7.app.NotificationCompat.MediaStyle()
|
||||
notificationBuilder.setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
|
||||
.setMediaSession(mediaSession.getSessionToken())
|
||||
.setShowActionsInCompactView(compactActionList.toArray())
|
||||
.setShowCancelButton(true)
|
||||
@ -1360,16 +1391,6 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
}
|
||||
}
|
||||
|
||||
private void stopWidgetUpdater() {
|
||||
taskManager.cancelWidgetUpdater();
|
||||
sendBroadcast(new Intent(STOP_WIDGET_UPDATE));
|
||||
}
|
||||
|
||||
private void updateWidget() {
|
||||
PlaybackService.this.sendBroadcast(new Intent(
|
||||
FORCE_WIDGET_UPDATE));
|
||||
}
|
||||
|
||||
public boolean sleepTimerActive() {
|
||||
return taskManager.isSleepTimerActive();
|
||||
}
|
||||
@ -1762,11 +1783,11 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
public boolean onMediaButtonEvent(final Intent mediaButton) {
|
||||
Log.d(TAG, "onMediaButtonEvent(" + mediaButton + ")");
|
||||
if (mediaButton != null) {
|
||||
KeyEvent keyEvent = (KeyEvent) mediaButton.getExtras().get(Intent.EXTRA_KEY_EVENT);
|
||||
KeyEvent keyEvent = (KeyEvent) mediaButton.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
|
||||
if (keyEvent != null &&
|
||||
keyEvent.getAction() == KeyEvent.ACTION_DOWN &&
|
||||
keyEvent.getRepeatCount() == 0) {
|
||||
return handleKeycode(keyEvent.getKeyCode(), keyEvent.getSource());
|
||||
return handleKeycode(keyEvent.getKeyCode(), false);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -13,7 +13,6 @@ import java.util.Map;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.Chapter;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.feed.FeedPreferences;
|
||||
@ -201,25 +200,15 @@ public final class DBReader {
|
||||
private static List<FeedItem> extractItemlistFromCursor(PodDBAdapter adapter, Cursor cursor) {
|
||||
List<FeedItem> result = new ArrayList<>(cursor.getCount());
|
||||
|
||||
LongList imageIds = new LongList(cursor.getCount());
|
||||
LongList itemIds = new LongList(cursor.getCount());
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
int indexImage = cursor.getColumnIndex(PodDBAdapter.KEY_IMAGE);
|
||||
long imageId = cursor.getLong(indexImage);
|
||||
imageIds.add(imageId);
|
||||
|
||||
FeedItem item = FeedItem.fromCursor(cursor);
|
||||
result.add(item);
|
||||
itemIds.add(item.getId());
|
||||
} while (cursor.moveToNext());
|
||||
Map<Long, FeedImage> images = getFeedImages(adapter, imageIds.toArray());
|
||||
Map<Long, FeedMedia> medias = getFeedMedia(adapter, itemIds);
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
FeedItem item = result.get(i);
|
||||
long imageId = imageIds.get(i);
|
||||
FeedImage image = images.get(imageId);
|
||||
item.setImage(image);
|
||||
for (FeedItem item : result) {
|
||||
FeedMedia media = medias.get(item.getId());
|
||||
item.setMedia(media);
|
||||
if (media != null) {
|
||||
@ -254,24 +243,9 @@ public final class DBReader {
|
||||
}
|
||||
|
||||
private static Feed extractFeedFromCursorRow(PodDBAdapter adapter, Cursor cursor) {
|
||||
final FeedImage image;
|
||||
int indexImage = cursor.getColumnIndex(PodDBAdapter.KEY_IMAGE);
|
||||
long imageId = cursor.getLong(indexImage);
|
||||
if (imageId != 0) {
|
||||
image = getFeedImage(adapter, imageId);
|
||||
} else {
|
||||
image = null;
|
||||
}
|
||||
|
||||
Feed feed = Feed.fromCursor(cursor);
|
||||
if (image != null) {
|
||||
feed.setImage(image);
|
||||
image.setOwner(feed);
|
||||
}
|
||||
|
||||
FeedPreferences preferences = FeedPreferences.fromCursor(cursor);
|
||||
feed.setPreferences(preferences);
|
||||
|
||||
return feed;
|
||||
}
|
||||
|
||||
@ -838,62 +812,6 @@ public final class DBReader {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the DB for a FeedImage of the given id.
|
||||
*
|
||||
* @param imageId The id of the object
|
||||
* @return The found object
|
||||
*/
|
||||
public static FeedImage getFeedImage(final long imageId) {
|
||||
Log.d(TAG, "getFeedImage() called with: " + "imageId = [" + imageId + "]");
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
try {
|
||||
return getFeedImage(adapter, imageId);
|
||||
} finally {
|
||||
adapter.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the DB for a FeedImage of the given id.
|
||||
*
|
||||
* @param imageId The id of the object
|
||||
* @return The found object
|
||||
*/
|
||||
private static FeedImage getFeedImage(PodDBAdapter adapter, final long imageId) {
|
||||
return getFeedImages(adapter, imageId).get(imageId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the DB for a FeedImage of the given id.
|
||||
*
|
||||
* @param imageIds The ids of the images
|
||||
* @return Map that associates the id of an image with the image itself
|
||||
*/
|
||||
private static Map<Long, FeedImage> getFeedImages(PodDBAdapter adapter, final long... imageIds) {
|
||||
String[] ids = new String[imageIds.length];
|
||||
for (int i = 0, len = imageIds.length; i < len; i++) {
|
||||
ids[i] = String.valueOf(imageIds[i]);
|
||||
}
|
||||
Cursor cursor = adapter.getImageCursor(ids);
|
||||
int imageCount = cursor.getCount();
|
||||
if (imageCount == 0) {
|
||||
cursor.close();
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<Long, FeedImage> result = new ArrayMap<>(imageCount);
|
||||
try {
|
||||
while (cursor.moveToNext()) {
|
||||
FeedImage image = FeedImage.fromCursor(cursor);
|
||||
result.put(image.getId(), image);
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the DB for a FeedMedia of the given id.
|
||||
*
|
||||
|
@ -4,6 +4,8 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -38,6 +40,7 @@ import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator;
|
||||
import de.danoeh.antennapod.core.util.exception.MediaFileNotFoundException;
|
||||
import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
@ -123,16 +126,13 @@ public final class DBTasks {
|
||||
media);
|
||||
}
|
||||
}
|
||||
// Start playback Service
|
||||
Intent launchIntent = new Intent(context, PlaybackService.class);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED,
|
||||
startWhenPrepared);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM,
|
||||
shouldStream);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY,
|
||||
true);
|
||||
context.startService(launchIntent);
|
||||
|
||||
new PlaybackServiceStarter(context, media)
|
||||
.callEvenIfRunning(true)
|
||||
.startWhenPrepared(startWhenPrepared)
|
||||
.shouldStream(shouldStream)
|
||||
.start();
|
||||
|
||||
if (showPlayer) {
|
||||
// Launch media player
|
||||
context.startActivity(PlaybackService.getPlayerActivityIntent(
|
||||
@ -155,42 +155,56 @@ public final class DBTasks {
|
||||
* Refreshes a given list of Feeds in a separate Thread. This method might ignore subsequent calls if it is still
|
||||
* enqueuing Feeds for download from a previous call
|
||||
*
|
||||
* @param context Might be used for accessing the database
|
||||
* @param feeds List of Feeds that should be refreshed.
|
||||
* @param context Might be used for accessing the database
|
||||
* @param feeds List of Feeds that should be refreshed.
|
||||
*/
|
||||
public static void refreshAllFeeds(final Context context,
|
||||
final List<Feed> feeds) {
|
||||
if (isRefreshing.compareAndSet(false, true)) {
|
||||
new Thread() {
|
||||
public void run() {
|
||||
if (feeds != null) {
|
||||
refreshFeeds(context, feeds);
|
||||
} else {
|
||||
refreshFeeds(context, DBReader.getFeedList());
|
||||
}
|
||||
isRefreshing.set(false);
|
||||
public static void refreshAllFeeds(final Context context, final List<Feed> feeds) {
|
||||
refreshAllFeeds(context, feeds, null);
|
||||
}
|
||||
|
||||
SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE);
|
||||
prefs.edit().putLong(PREF_LAST_REFRESH, System.currentTimeMillis()).apply();
|
||||
|
||||
if (FlattrUtils.hasToken()) {
|
||||
Log.d(TAG, "Flattring all pending things.");
|
||||
new FlattrClickWorker(context).executeAsync(); // flattr pending things
|
||||
|
||||
Log.d(TAG, "Fetching flattr status.");
|
||||
new FlattrStatusFetcher(context).start();
|
||||
|
||||
}
|
||||
if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) {
|
||||
GpodnetSyncService.sendSyncIntent(context);
|
||||
}
|
||||
Log.d(TAG, "refreshAllFeeds autodownload");
|
||||
autodownloadUndownloadedItems(context);
|
||||
}
|
||||
}.start();
|
||||
} else {
|
||||
/**
|
||||
* Refreshes a given list of Feeds in a separate Thread. This method might ignore subsequent calls if it is still
|
||||
* enqueuing Feeds for download from a previous call
|
||||
*
|
||||
* @param context Might be used for accessing the database
|
||||
* @param feeds List of Feeds that should be refreshed.
|
||||
* @param callback Called after everything was added enqueued for download. Might be null.
|
||||
*/
|
||||
public static void refreshAllFeeds(final Context context, final List<Feed> feeds, @Nullable Runnable callback) {
|
||||
if (!isRefreshing.compareAndSet(false, true)) {
|
||||
Log.d(TAG, "Ignoring request to refresh all feeds: Refresh lock is locked");
|
||||
return;
|
||||
}
|
||||
|
||||
new Thread(() -> {
|
||||
if (feeds != null) {
|
||||
refreshFeeds(context, feeds);
|
||||
} else {
|
||||
refreshFeeds(context, DBReader.getFeedList());
|
||||
}
|
||||
isRefreshing.set(false);
|
||||
|
||||
SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE);
|
||||
prefs.edit().putLong(PREF_LAST_REFRESH, System.currentTimeMillis()).apply();
|
||||
|
||||
if (FlattrUtils.hasToken()) {
|
||||
Log.d(TAG, "Flattring all pending things.");
|
||||
new FlattrClickWorker(context).executeAsync(); // flattr pending things
|
||||
|
||||
Log.d(TAG, "Fetching flattr status.");
|
||||
new FlattrStatusFetcher(context).start();
|
||||
|
||||
}
|
||||
if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) {
|
||||
GpodnetSyncService.sendSyncIntent(context);
|
||||
}
|
||||
Log.d(TAG, "refreshAllFeeds autodownload");
|
||||
autodownloadUndownloadedItems(context);
|
||||
|
||||
if (callback != null) {
|
||||
callback.run();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,292 @@
|
||||
package de.danoeh.antennapod.core.storage;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
|
||||
class DBUpgrader {
|
||||
/**
|
||||
* Upgrades the given database to a new schema version
|
||||
*/
|
||||
static void upgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
|
||||
if (oldVersion <= 1) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN "
|
||||
+ PodDBAdapter.KEY_TYPE + " TEXT");
|
||||
}
|
||||
if (oldVersion <= 2) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_LINK + " TEXT");
|
||||
}
|
||||
if (oldVersion <= 3) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_ITEM_IDENTIFIER + " TEXT");
|
||||
}
|
||||
if (oldVersion <= 4) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN "
|
||||
+ PodDBAdapter.KEY_FEED_IDENTIFIER + " TEXT");
|
||||
}
|
||||
if (oldVersion <= 5) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_DOWNLOAD_LOG
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_REASON_DETAILED + " TEXT");
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_DOWNLOAD_LOG
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_DOWNLOADSTATUS_TITLE + " TEXT");
|
||||
}
|
||||
if (oldVersion <= 6) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_CHAPTER_TYPE + " INTEGER");
|
||||
}
|
||||
if (oldVersion <= 7) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_PLAYBACK_COMPLETION_DATE
|
||||
+ " INTEGER");
|
||||
}
|
||||
if (oldVersion <= 8) {
|
||||
final int KEY_ID_POSITION = 0;
|
||||
final int KEY_MEDIA_POSITION = 1;
|
||||
|
||||
// Add feeditem column to feedmedia table
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_FEEDITEM
|
||||
+ " INTEGER");
|
||||
Cursor feeditemCursor = db.query(PodDBAdapter.TABLE_NAME_FEED_ITEMS,
|
||||
new String[]{PodDBAdapter.KEY_ID, PodDBAdapter.KEY_MEDIA}, "? > 0",
|
||||
new String[]{PodDBAdapter.KEY_MEDIA}, null, null, null);
|
||||
if (feeditemCursor.moveToFirst()) {
|
||||
db.beginTransaction();
|
||||
ContentValues contentValues = new ContentValues();
|
||||
do {
|
||||
long mediaId = feeditemCursor.getLong(KEY_MEDIA_POSITION);
|
||||
contentValues.put(PodDBAdapter.KEY_FEEDITEM, feeditemCursor.getLong(KEY_ID_POSITION));
|
||||
db.update(PodDBAdapter.TABLE_NAME_FEED_MEDIA, contentValues, PodDBAdapter.KEY_ID + "=?", new String[]{String.valueOf(mediaId)});
|
||||
contentValues.clear();
|
||||
} while (feeditemCursor.moveToNext());
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
feeditemCursor.close();
|
||||
}
|
||||
if (oldVersion <= 9) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_AUTO_DOWNLOAD
|
||||
+ " INTEGER DEFAULT 1");
|
||||
}
|
||||
if (oldVersion <= 10) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_FLATTR_STATUS
|
||||
+ " INTEGER");
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_FLATTR_STATUS
|
||||
+ " INTEGER");
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_PLAYED_DURATION
|
||||
+ " INTEGER");
|
||||
}
|
||||
if (oldVersion <= 11) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_USERNAME
|
||||
+ " TEXT");
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_PASSWORD
|
||||
+ " TEXT");
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_IMAGE
|
||||
+ " INTEGER");
|
||||
}
|
||||
if (oldVersion <= 12) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_IS_PAGED + " INTEGER DEFAULT 0");
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_NEXT_PAGE_LINK + " TEXT");
|
||||
}
|
||||
if (oldVersion <= 13) {
|
||||
// remove duplicate rows in "Chapters" table that were created because of a bug.
|
||||
db.execSQL(String.format("DELETE FROM %s WHERE %s NOT IN " +
|
||||
"(SELECT MIN(%s) as %s FROM %s GROUP BY %s,%s,%s,%s,%s)",
|
||||
PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS,
|
||||
PodDBAdapter.KEY_ID,
|
||||
PodDBAdapter.KEY_ID,
|
||||
PodDBAdapter.KEY_ID,
|
||||
PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS,
|
||||
PodDBAdapter.KEY_TITLE,
|
||||
PodDBAdapter.KEY_START,
|
||||
PodDBAdapter.KEY_FEEDITEM,
|
||||
PodDBAdapter.KEY_LINK,
|
||||
PodDBAdapter.KEY_CHAPTER_TYPE));
|
||||
}
|
||||
if (oldVersion <= 14) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_AUTO_DOWNLOAD + " INTEGER");
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
|
||||
+ " SET " + PodDBAdapter.KEY_AUTO_DOWNLOAD + " = "
|
||||
+ "(SELECT " + PodDBAdapter.KEY_AUTO_DOWNLOAD
|
||||
+ " FROM " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " WHERE " + PodDBAdapter.TABLE_NAME_FEEDS + "." + PodDBAdapter.KEY_ID
|
||||
+ " = " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_FEED + ")");
|
||||
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_HIDE + " TEXT");
|
||||
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_LAST_UPDATE_FAILED + " INTEGER DEFAULT 0");
|
||||
|
||||
// create indexes
|
||||
db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_FEED);
|
||||
db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDMEDIA_FEEDITEM);
|
||||
db.execSQL(PodDBAdapter.CREATE_INDEX_QUEUE_FEEDITEM);
|
||||
db.execSQL(PodDBAdapter.CREATE_INDEX_SIMPLECHAPTERS_FEEDITEM);
|
||||
}
|
||||
if (oldVersion <= 15) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_HAS_EMBEDDED_PICTURE + " INTEGER DEFAULT -1");
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " SET " + PodDBAdapter.KEY_HAS_EMBEDDED_PICTURE + "=0"
|
||||
+ " WHERE " + PodDBAdapter.KEY_DOWNLOADED + "=0");
|
||||
Cursor c = db.rawQuery("SELECT " + PodDBAdapter.KEY_FILE_URL
|
||||
+ " FROM " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " WHERE " + PodDBAdapter.KEY_DOWNLOADED + "=1 "
|
||||
+ " AND " + PodDBAdapter.KEY_HAS_EMBEDDED_PICTURE + "=-1", null);
|
||||
if (c.moveToFirst()) {
|
||||
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
|
||||
do {
|
||||
String fileUrl = c.getString(0);
|
||||
try {
|
||||
mmr.setDataSource(fileUrl);
|
||||
byte[] image = mmr.getEmbeddedPicture();
|
||||
if (image != null) {
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " SET " + PodDBAdapter.KEY_HAS_EMBEDDED_PICTURE + "=1"
|
||||
+ " WHERE " + PodDBAdapter.KEY_FILE_URL + "='" + fileUrl + "'");
|
||||
} else {
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " SET " + PodDBAdapter.KEY_HAS_EMBEDDED_PICTURE + "=0"
|
||||
+ " WHERE " + PodDBAdapter.KEY_FILE_URL + "='" + fileUrl + "'");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} while (c.moveToNext());
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
if (oldVersion <= 16) {
|
||||
String selectNew = "SELECT " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_ID
|
||||
+ " FROM " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
|
||||
+ " INNER JOIN " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + " ON "
|
||||
+ PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_ID + "="
|
||||
+ PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_FEEDITEM
|
||||
+ " LEFT OUTER JOIN " + PodDBAdapter.TABLE_NAME_QUEUE + " ON "
|
||||
+ PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_ID + "="
|
||||
+ PodDBAdapter.TABLE_NAME_QUEUE + "." + PodDBAdapter.KEY_FEEDITEM
|
||||
+ " WHERE "
|
||||
+ PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_READ + " = 0 AND " // unplayed
|
||||
+ PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_DOWNLOADED + " = 0 AND " // undownloaded
|
||||
+ PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_POSITION + " = 0 AND " // not partially played
|
||||
+ PodDBAdapter.TABLE_NAME_QUEUE + "." + PodDBAdapter.KEY_ID + " IS NULL"; // not in queue
|
||||
String sql = "UPDATE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
|
||||
+ " SET " + PodDBAdapter.KEY_READ + "=" + FeedItem.NEW
|
||||
+ " WHERE " + PodDBAdapter.KEY_ID + " IN (" + selectNew + ")";
|
||||
Log.d("Migration", "SQL: " + sql);
|
||||
db.execSQL(sql);
|
||||
}
|
||||
if (oldVersion <= 17) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_AUTO_DELETE_ACTION + " INTEGER DEFAULT 0");
|
||||
}
|
||||
if (oldVersion < 1030005) {
|
||||
db.execSQL("UPDATE FeedItems SET auto_download=0 WHERE " +
|
||||
"(read=1 OR id IN (SELECT feeditem FROM FeedMedia WHERE position>0 OR downloaded=1)) " +
|
||||
"AND id NOT IN (SELECT feeditem FROM Queue)");
|
||||
}
|
||||
if (oldVersion < 1040001) {
|
||||
db.execSQL(PodDBAdapter.CREATE_TABLE_FAVORITES);
|
||||
}
|
||||
if (oldVersion < 1040002) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_LAST_PLAYED_TIME + " INTEGER DEFAULT 0");
|
||||
}
|
||||
if (oldVersion < 1040013) {
|
||||
db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_PUBDATE);
|
||||
db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_READ);
|
||||
}
|
||||
if (oldVersion < 1050003) {
|
||||
// Migrates feed list filter data
|
||||
|
||||
db.beginTransaction();
|
||||
|
||||
// Change to intermediate values to avoid overwriting in the following find/replace
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + PodDBAdapter.KEY_HIDE + " = replace(" + PodDBAdapter.KEY_HIDE + ", 'unplayed', 'noplay')");
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + PodDBAdapter.KEY_HIDE + " = replace(" + PodDBAdapter.KEY_HIDE + ", 'not_queued', 'noqueue')");
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + PodDBAdapter.KEY_HIDE + " = replace(" + PodDBAdapter.KEY_HIDE + ", 'not_downloaded', 'nodl')");
|
||||
|
||||
// Replace played, queued, and downloaded with their opposites
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + PodDBAdapter.KEY_HIDE + " = replace(" + PodDBAdapter.KEY_HIDE + ", 'played', 'unplayed')");
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + PodDBAdapter.KEY_HIDE + " = replace(" + PodDBAdapter.KEY_HIDE + ", 'queued', 'not_queued')");
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + PodDBAdapter.KEY_HIDE + " = replace(" + PodDBAdapter.KEY_HIDE + ", 'downloaded', 'not_downloaded')");
|
||||
|
||||
// Now replace intermediates for unplayed, not queued, etc. with their opposites
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + PodDBAdapter.KEY_HIDE + " = replace(" + PodDBAdapter.KEY_HIDE + ", 'noplay', 'played')");
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + PodDBAdapter.KEY_HIDE + " = replace(" + PodDBAdapter.KEY_HIDE + ", 'noqueue', 'queued')");
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + PodDBAdapter.KEY_HIDE + " = replace(" + PodDBAdapter.KEY_HIDE + ", 'nodl', 'downloaded')");
|
||||
|
||||
// Paused doesn't have an opposite, so unplayed is the next best option
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + PodDBAdapter.KEY_HIDE + " = replace(" + PodDBAdapter.KEY_HIDE + ", 'paused', 'unplayed')");
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
|
||||
// and now get ready for autodownload filters
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_INCLUDE_FILTER + " TEXT DEFAULT ''");
|
||||
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_EXCLUDE_FILTER + " TEXT DEFAULT ''");
|
||||
|
||||
// and now auto refresh
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_KEEP_UPDATED + " INTEGER DEFAULT 1");
|
||||
}
|
||||
if (oldVersion < 1050004) {
|
||||
// prevent old timestamps to be misinterpreted as ETags
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " SET " + PodDBAdapter.KEY_LASTUPDATE + "=NULL");
|
||||
}
|
||||
if (oldVersion < 1060200) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_CUSTOM_TITLE + " TEXT");
|
||||
}
|
||||
if (oldVersion < 1060596) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_IMAGE_URL + " TEXT");
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_IMAGE_URL + " TEXT");
|
||||
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + " SET " + PodDBAdapter.KEY_IMAGE_URL + " = ("
|
||||
+ " SELECT " + PodDBAdapter.KEY_DOWNLOAD_URL
|
||||
+ " FROM " + PodDBAdapter.TABLE_NAME_FEED_IMAGES
|
||||
+ " WHERE " + PodDBAdapter.TABLE_NAME_FEED_IMAGES + "." + PodDBAdapter.KEY_ID
|
||||
+ " = " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_IMAGE + ")");
|
||||
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS + " SET " + PodDBAdapter.KEY_IMAGE_URL + " = ("
|
||||
+ " SELECT " + PodDBAdapter.KEY_DOWNLOAD_URL
|
||||
+ " FROM " + PodDBAdapter.TABLE_NAME_FEED_IMAGES
|
||||
+ " WHERE " + PodDBAdapter.TABLE_NAME_FEED_IMAGES + "." + PodDBAdapter.KEY_ID
|
||||
+ " = " + PodDBAdapter.TABLE_NAME_FEEDS + "." + PodDBAdapter.KEY_IMAGE + ")");
|
||||
|
||||
db.execSQL("DROP TABLE " + PodDBAdapter.TABLE_NAME_FEED_IMAGES);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -32,7 +32,6 @@ import de.danoeh.antennapod.core.event.QueueEvent;
|
||||
import de.danoeh.antennapod.core.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedEvent;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.feed.FeedPreferences;
|
||||
@ -166,17 +165,6 @@ public class DBWriter {
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
// delete image file
|
||||
if (feed.getImage() != null) {
|
||||
if (feed.getImage().isDownloaded()
|
||||
&& feed.getImage().getFile_url() != null) {
|
||||
File imageFile = new File(feed.getImage()
|
||||
.getFile_url());
|
||||
imageFile.delete();
|
||||
} else if (requester.isDownloadingFile(feed.getImage())) {
|
||||
requester.cancelDownload(context, feed.getImage());
|
||||
}
|
||||
}
|
||||
// delete stored media files and mark them as read
|
||||
List<FeedItem> queue = DBReader.getQueue();
|
||||
List<FeedItem> removed = new ArrayList<>();
|
||||
@ -188,6 +176,9 @@ public class DBWriter {
|
||||
if(queue.remove(item)) {
|
||||
removed.add(item);
|
||||
}
|
||||
if (item.getState() == FeedItem.State.PLAYING && PlaybackService.isRunning) {
|
||||
context.stopService(new Intent(context, PlaybackService.class));
|
||||
}
|
||||
if (item.getMedia() != null
|
||||
&& item.getMedia().isDownloaded()) {
|
||||
File mediaFile = new File(item.getMedia()
|
||||
@ -197,16 +188,6 @@ public class DBWriter {
|
||||
&& requester.isDownloadingFile(item.getMedia())) {
|
||||
requester.cancelDownload(context, item.getMedia());
|
||||
}
|
||||
|
||||
if (item.hasItemImage()) {
|
||||
FeedImage image = item.getImage();
|
||||
if (image.isDownloaded() && image.getFile_url() != null) {
|
||||
File imgFile = new File(image.getFile_url());
|
||||
imgFile.delete();
|
||||
} else if (requester.isDownloadingFile(image)) {
|
||||
requester.cancelDownload(context, item.getImage());
|
||||
}
|
||||
}
|
||||
}
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
@ -782,21 +763,6 @@ public class DBWriter {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a FeedImage object in the database. This method will save all attributes of the FeedImage object. The
|
||||
* contents of FeedComponent-attributes (e.g. the FeedImages's 'feed'-attribute) will not be saved.
|
||||
*
|
||||
* @param image The FeedImage object.
|
||||
*/
|
||||
public static Future<?> setFeedImage(final FeedImage image) {
|
||||
return dbExec.submit(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setImage(image);
|
||||
adapter.close();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates download URL of a feed
|
||||
*/
|
||||
|
@ -4,6 +4,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.webkit.URLUtil;
|
||||
@ -81,7 +82,7 @@ public class DownloadRequester {
|
||||
|
||||
Intent launchIntent = new Intent(context, DownloadService.class);
|
||||
launchIntent.putExtra(DownloadService.EXTRA_REQUEST, request);
|
||||
context.startService(launchIntent);
|
||||
ContextCompat.startForegroundService(context, launchIntent);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -176,8 +177,8 @@ public class DownloadRequester {
|
||||
args.putInt(REQUEST_ARG_PAGE_NR, feed.getPageNr());
|
||||
args.putBoolean(REQUEST_ARG_LOAD_ALL_PAGES, loadAllPages);
|
||||
|
||||
download(context, feed, null, new File(getFeedfilePath(context),
|
||||
getFeedfileName(feed)), true, username, password, lastModified, true, args);
|
||||
download(context, feed, null, new File(getFeedfilePath(), getFeedfileName(feed)),
|
||||
true, username, password, lastModified, true, args);
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,8 +204,7 @@ public class DownloadRequester {
|
||||
if (feedmedia.getFile_url() != null) {
|
||||
dest = new File(feedmedia.getFile_url());
|
||||
} else {
|
||||
dest = new File(getMediafilePath(context, feedmedia),
|
||||
getMediafilename(feedmedia));
|
||||
dest = new File(getMediafilePath(feedmedia), getMediafilename(feedmedia));
|
||||
}
|
||||
download(context, feedmedia, feed,
|
||||
dest, false, username, password, null, false, null);
|
||||
@ -305,10 +305,8 @@ public class DownloadRequester {
|
||||
return downloads.size();
|
||||
}
|
||||
|
||||
private synchronized String getFeedfilePath(Context context)
|
||||
throws DownloadRequestException {
|
||||
return getExternalFilesDirOrThrowException(context, FEED_DOWNLOADPATH)
|
||||
.toString() + "/";
|
||||
private synchronized String getFeedfilePath() throws DownloadRequestException {
|
||||
return getExternalFilesDirOrThrowException(FEED_DOWNLOADPATH).toString() + "/";
|
||||
}
|
||||
|
||||
private synchronized String getFeedfileName(Feed feed) {
|
||||
@ -319,10 +317,8 @@ public class DownloadRequester {
|
||||
return "feed-" + FileNameGenerator.generateFileName(filename);
|
||||
}
|
||||
|
||||
private synchronized String getMediafilePath(Context context, FeedMedia media)
|
||||
throws DownloadRequestException {
|
||||
private synchronized String getMediafilePath(FeedMedia media) throws DownloadRequestException {
|
||||
File externalStorage = getExternalFilesDirOrThrowException(
|
||||
context,
|
||||
MEDIA_DOWNLOADPATH
|
||||
+ FileNameGenerator.generateFileName(media.getItem()
|
||||
.getFeed().getTitle()) + "/"
|
||||
@ -330,8 +326,7 @@ public class DownloadRequester {
|
||||
return externalStorage.toString();
|
||||
}
|
||||
|
||||
private File getExternalFilesDirOrThrowException(Context context,
|
||||
String type) throws DownloadRequestException {
|
||||
private File getExternalFilesDirOrThrowException(String type) throws DownloadRequestException {
|
||||
File result = UserPreferences.getDataFolder(type);
|
||||
if (result == null) {
|
||||
throw new DownloadRequestException(
|
||||
|
@ -14,20 +14,10 @@ import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import de.danoeh.antennapod.core.R;
|
||||
import de.danoeh.antennapod.core.event.ProgressEvent;
|
||||
import de.danoeh.antennapod.core.feed.Chapter;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedComponent;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.feed.FeedPreferences;
|
||||
@ -38,6 +28,13 @@ import de.danoeh.antennapod.core.util.flattr.FlattrStatus;
|
||||
import de.greenrobot.event.EventBus;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
// TODO Remove media column from feeditem table
|
||||
|
||||
/**
|
||||
@ -74,8 +71,9 @@ public class PodDBAdapter {
|
||||
public static final String KEY_SIZE = "filesize";
|
||||
public static final String KEY_MIME_TYPE = "mime_type";
|
||||
public static final String KEY_IMAGE = "image";
|
||||
public static final String KEY_IMAGE_URL = "image_url";
|
||||
public static final String KEY_FEED = "feed";
|
||||
private static final String KEY_MEDIA = "media";
|
||||
public static final String KEY_MEDIA = "media";
|
||||
public static final String KEY_DOWNLOADED = "downloaded";
|
||||
public static final String KEY_LASTUPDATE = "last_update";
|
||||
public static final String KEY_FEEDFILE = "feedfile";
|
||||
@ -114,14 +112,14 @@ public class PodDBAdapter {
|
||||
public static final String KEY_EXCLUDE_FILTER = "exclude_filter";
|
||||
|
||||
// Table names
|
||||
private static final String TABLE_NAME_FEEDS = "Feeds";
|
||||
private static final String TABLE_NAME_FEED_ITEMS = "FeedItems";
|
||||
private static final String TABLE_NAME_FEED_IMAGES = "FeedImages";
|
||||
private static final String TABLE_NAME_FEED_MEDIA = "FeedMedia";
|
||||
private static final String TABLE_NAME_DOWNLOAD_LOG = "DownloadLog";
|
||||
private static final String TABLE_NAME_QUEUE = "Queue";
|
||||
private static final String TABLE_NAME_SIMPLECHAPTERS = "SimpleChapters";
|
||||
private static final String TABLE_NAME_FAVORITES = "Favorites";
|
||||
static final String TABLE_NAME_FEEDS = "Feeds";
|
||||
static final String TABLE_NAME_FEED_ITEMS = "FeedItems";
|
||||
static final String TABLE_NAME_FEED_IMAGES = "FeedImages";
|
||||
static final String TABLE_NAME_FEED_MEDIA = "FeedMedia";
|
||||
static final String TABLE_NAME_DOWNLOAD_LOG = "DownloadLog";
|
||||
static final String TABLE_NAME_QUEUE = "Queue";
|
||||
static final String TABLE_NAME_SIMPLECHAPTERS = "SimpleChapters";
|
||||
static final String TABLE_NAME_FAVORITES = "Favorites";
|
||||
|
||||
// SQL Statements for creating new tables
|
||||
private static final String TABLE_PRIMARY_KEY = KEY_ID
|
||||
@ -133,7 +131,7 @@ public class PodDBAdapter {
|
||||
+ KEY_DOWNLOADED + " INTEGER," + KEY_LINK + " TEXT,"
|
||||
+ KEY_DESCRIPTION + " TEXT," + KEY_PAYMENT_LINK + " TEXT,"
|
||||
+ KEY_LASTUPDATE + " TEXT," + KEY_LANGUAGE + " TEXT," + KEY_AUTHOR
|
||||
+ " TEXT," + KEY_IMAGE + " INTEGER," + KEY_TYPE + " TEXT,"
|
||||
+ " TEXT," + KEY_IMAGE_URL + " TEXT," + KEY_TYPE + " TEXT,"
|
||||
+ KEY_FEED_IDENTIFIER + " TEXT," + KEY_AUTO_DOWNLOAD + " INTEGER DEFAULT 1,"
|
||||
+ KEY_FLATTR_STATUS + " INTEGER,"
|
||||
+ KEY_USERNAME + " TEXT,"
|
||||
@ -155,14 +153,9 @@ public class PodDBAdapter {
|
||||
+ KEY_MEDIA + " INTEGER," + KEY_FEED + " INTEGER,"
|
||||
+ KEY_HAS_CHAPTERS + " INTEGER," + KEY_ITEM_IDENTIFIER + " TEXT,"
|
||||
+ KEY_FLATTR_STATUS + " INTEGER,"
|
||||
+ KEY_IMAGE + " INTEGER,"
|
||||
+ KEY_IMAGE_URL + " TEXT,"
|
||||
+ KEY_AUTO_DOWNLOAD + " INTEGER)";
|
||||
|
||||
private static final String CREATE_TABLE_FEED_IMAGES = "CREATE TABLE "
|
||||
+ TABLE_NAME_FEED_IMAGES + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
|
||||
+ " TEXT," + KEY_FILE_URL + " TEXT," + KEY_DOWNLOAD_URL + " TEXT,"
|
||||
+ KEY_DOWNLOADED + " INTEGER)";
|
||||
|
||||
private static final String CREATE_TABLE_FEED_MEDIA = "CREATE TABLE "
|
||||
+ TABLE_NAME_FEED_MEDIA + " (" + TABLE_PRIMARY_KEY + KEY_DURATION
|
||||
+ " INTEGER," + KEY_FILE_URL + " TEXT," + KEY_DOWNLOAD_URL
|
||||
@ -191,36 +184,31 @@ public class PodDBAdapter {
|
||||
+ KEY_LINK + " TEXT," + KEY_CHAPTER_TYPE + " INTEGER)";
|
||||
|
||||
// SQL Statements for creating indexes
|
||||
private static final String CREATE_INDEX_FEEDITEMS_FEED = "CREATE INDEX "
|
||||
static final String CREATE_INDEX_FEEDITEMS_FEED = "CREATE INDEX "
|
||||
+ TABLE_NAME_FEED_ITEMS + "_" + KEY_FEED + " ON " + TABLE_NAME_FEED_ITEMS + " ("
|
||||
+ KEY_FEED + ")";
|
||||
|
||||
private static final String CREATE_INDEX_FEEDITEMS_IMAGE = "CREATE INDEX "
|
||||
+ TABLE_NAME_FEED_ITEMS + "_" + KEY_IMAGE + " ON " + TABLE_NAME_FEED_ITEMS + " ("
|
||||
+ KEY_IMAGE + ")";
|
||||
|
||||
private static final String CREATE_INDEX_FEEDITEMS_PUBDATE = "CREATE INDEX IF NOT EXISTS "
|
||||
static final String CREATE_INDEX_FEEDITEMS_PUBDATE = "CREATE INDEX IF NOT EXISTS "
|
||||
+ TABLE_NAME_FEED_ITEMS + "_" + KEY_PUBDATE + " ON " + TABLE_NAME_FEED_ITEMS + " ("
|
||||
+ KEY_PUBDATE + ")";
|
||||
|
||||
private static final String CREATE_INDEX_FEEDITEMS_READ = "CREATE INDEX IF NOT EXISTS "
|
||||
static final String CREATE_INDEX_FEEDITEMS_READ = "CREATE INDEX IF NOT EXISTS "
|
||||
+ TABLE_NAME_FEED_ITEMS + "_" + KEY_READ + " ON " + TABLE_NAME_FEED_ITEMS + " ("
|
||||
+ KEY_READ + ")";
|
||||
|
||||
|
||||
private static final String CREATE_INDEX_QUEUE_FEEDITEM = "CREATE INDEX "
|
||||
static final String CREATE_INDEX_QUEUE_FEEDITEM = "CREATE INDEX "
|
||||
+ TABLE_NAME_QUEUE + "_" + KEY_FEEDITEM + " ON " + TABLE_NAME_QUEUE + " ("
|
||||
+ KEY_FEEDITEM + ")";
|
||||
|
||||
private static final String CREATE_INDEX_FEEDMEDIA_FEEDITEM = "CREATE INDEX "
|
||||
static final String CREATE_INDEX_FEEDMEDIA_FEEDITEM = "CREATE INDEX "
|
||||
+ TABLE_NAME_FEED_MEDIA + "_" + KEY_FEEDITEM + " ON " + TABLE_NAME_FEED_MEDIA + " ("
|
||||
+ KEY_FEEDITEM + ")";
|
||||
|
||||
private static final String CREATE_INDEX_SIMPLECHAPTERS_FEEDITEM = "CREATE INDEX "
|
||||
static final String CREATE_INDEX_SIMPLECHAPTERS_FEEDITEM = "CREATE INDEX "
|
||||
+ TABLE_NAME_SIMPLECHAPTERS + "_" + KEY_FEEDITEM + " ON " + TABLE_NAME_SIMPLECHAPTERS + " ("
|
||||
+ KEY_FEEDITEM + ")";
|
||||
|
||||
private static final String CREATE_TABLE_FAVORITES = "CREATE TABLE "
|
||||
static final String CREATE_TABLE_FAVORITES = "CREATE TABLE "
|
||||
+ TABLE_NAME_FAVORITES + "(" + KEY_ID + " INTEGER PRIMARY KEY,"
|
||||
+ KEY_FEEDITEM + " INTEGER," + KEY_FEED + " INTEGER)";
|
||||
|
||||
@ -240,7 +228,7 @@ public class PodDBAdapter {
|
||||
TABLE_NAME_FEEDS + "." + KEY_LASTUPDATE,
|
||||
TABLE_NAME_FEEDS + "." + KEY_LANGUAGE,
|
||||
TABLE_NAME_FEEDS + "." + KEY_AUTHOR,
|
||||
TABLE_NAME_FEEDS + "." + KEY_IMAGE,
|
||||
TABLE_NAME_FEEDS + "." + KEY_IMAGE_URL,
|
||||
TABLE_NAME_FEEDS + "." + KEY_TYPE,
|
||||
TABLE_NAME_FEEDS + "." + KEY_FEED_IDENTIFIER,
|
||||
TABLE_NAME_FEEDS + "." + KEY_AUTO_DOWNLOAD,
|
||||
@ -273,7 +261,7 @@ public class PodDBAdapter {
|
||||
TABLE_NAME_FEED_ITEMS + "." + KEY_HAS_CHAPTERS,
|
||||
TABLE_NAME_FEED_ITEMS + "." + KEY_ITEM_IDENTIFIER,
|
||||
TABLE_NAME_FEED_ITEMS + "." + KEY_FLATTR_STATUS,
|
||||
TABLE_NAME_FEED_ITEMS + "." + KEY_IMAGE,
|
||||
TABLE_NAME_FEED_ITEMS + "." + KEY_IMAGE_URL,
|
||||
TABLE_NAME_FEED_ITEMS + "." + KEY_AUTO_DOWNLOAD
|
||||
};
|
||||
|
||||
@ -283,7 +271,6 @@ public class PodDBAdapter {
|
||||
private static final String[] ALL_TABLES = {
|
||||
TABLE_NAME_FEEDS,
|
||||
TABLE_NAME_FEED_ITEMS,
|
||||
TABLE_NAME_FEED_IMAGES,
|
||||
TABLE_NAME_FEED_MEDIA,
|
||||
TABLE_NAME_DOWNLOAD_LOG,
|
||||
TABLE_NAME_QUEUE,
|
||||
@ -388,12 +375,7 @@ public class PodDBAdapter {
|
||||
values.put(KEY_PAYMENT_LINK, feed.getPaymentLink());
|
||||
values.put(KEY_AUTHOR, feed.getAuthor());
|
||||
values.put(KEY_LANGUAGE, feed.getLanguage());
|
||||
if (feed.getImage() != null) {
|
||||
if (feed.getImage().getId() == 0) {
|
||||
setImage(feed.getImage());
|
||||
}
|
||||
values.put(KEY_IMAGE, feed.getImage().getId());
|
||||
}
|
||||
values.put(KEY_IMAGE_URL, feed.getImageUrl());
|
||||
|
||||
values.put(KEY_FILE_URL, feed.getFile_url());
|
||||
values.put(KEY_DOWNLOAD_URL, feed.getDownload_url());
|
||||
@ -450,54 +432,7 @@ public class PodDBAdapter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts or updates an image entry
|
||||
*
|
||||
* @return the id of the entry
|
||||
*/
|
||||
public long setImage(FeedImage image) {
|
||||
boolean startedTransaction = false;
|
||||
|
||||
try {
|
||||
if (!db.inTransaction()) {
|
||||
db.beginTransactionNonExclusive();
|
||||
startedTransaction = true;
|
||||
}
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(KEY_TITLE, image.getTitle());
|
||||
values.put(KEY_DOWNLOAD_URL, image.getDownload_url());
|
||||
values.put(KEY_DOWNLOADED, image.isDownloaded());
|
||||
values.put(KEY_FILE_URL, image.getFile_url());
|
||||
if (image.getId() == 0) {
|
||||
image.setId(db.insert(TABLE_NAME_FEED_IMAGES, null, values));
|
||||
} else {
|
||||
db.update(TABLE_NAME_FEED_IMAGES, values, KEY_ID + "=?",
|
||||
new String[]{String.valueOf(image.getId())});
|
||||
}
|
||||
|
||||
final FeedComponent owner = image.getOwner();
|
||||
if (owner != null && owner.getId() != 0) {
|
||||
values.clear();
|
||||
values.put(KEY_IMAGE, image.getId());
|
||||
if (owner instanceof Feed) {
|
||||
db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(image.getOwner().getId())});
|
||||
}
|
||||
}
|
||||
if (startedTransaction) {
|
||||
db.setTransactionSuccessful();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
} finally {
|
||||
if (startedTransaction) {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
return image.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts or updates an image entry
|
||||
* Inserts or updates a media entry
|
||||
*
|
||||
* @return the id of the entry
|
||||
*/
|
||||
@ -759,12 +694,7 @@ public class PodDBAdapter {
|
||||
values.put(KEY_ITEM_IDENTIFIER, item.getItemIdentifier());
|
||||
values.put(KEY_FLATTR_STATUS, item.getFlattrStatus().toLong());
|
||||
values.put(KEY_AUTO_DOWNLOAD, item.getAutoDownload());
|
||||
if (item.hasItemImage()) {
|
||||
if (item.getImage().getId() == 0) {
|
||||
setImage(item.getImage());
|
||||
}
|
||||
values.put(KEY_IMAGE, item.getImage().getId());
|
||||
}
|
||||
values.put(KEY_IMAGE_URL, item.getImageUrl());
|
||||
|
||||
if (item.getId() == 0) {
|
||||
item.setId(db.insert(TABLE_NAME_FEED_ITEMS, null, values));
|
||||
@ -993,11 +923,6 @@ public class PodDBAdapter {
|
||||
new String[]{String.valueOf(item.getId())});
|
||||
}
|
||||
|
||||
private void removeFeedImage(FeedImage image) {
|
||||
db.delete(TABLE_NAME_FEED_IMAGES, KEY_ID + "=?",
|
||||
new String[]{String.valueOf(image.getId())});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a FeedItem and its FeedMedia entry.
|
||||
*/
|
||||
@ -1008,9 +933,6 @@ public class PodDBAdapter {
|
||||
if (item.hasChapters() || item.getChapters() != null) {
|
||||
removeChaptersOfItem(item);
|
||||
}
|
||||
if (item.hasItemImage()) {
|
||||
removeFeedImage(item.getImage());
|
||||
}
|
||||
db.delete(TABLE_NAME_FEED_ITEMS, KEY_ID + "=?",
|
||||
new String[]{String.valueOf(item.getId())});
|
||||
}
|
||||
@ -1021,9 +943,6 @@ public class PodDBAdapter {
|
||||
public void removeFeed(Feed feed) {
|
||||
try {
|
||||
db.beginTransactionNonExclusive();
|
||||
if (feed.getImage() != null) {
|
||||
removeFeedImage(feed.getImage());
|
||||
}
|
||||
if (feed.getItems() != null) {
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
removeFeedItem(item);
|
||||
@ -1363,17 +1282,12 @@ public class PodDBAdapter {
|
||||
public Cursor getImageAuthenticationCursor(final String imageUrl) {
|
||||
String downloadUrl = DatabaseUtils.sqlEscapeString(imageUrl);
|
||||
final String query = ""
|
||||
+ "SELECT " + KEY_USERNAME + "," + KEY_PASSWORD + " FROM " + TABLE_NAME_FEED_IMAGES
|
||||
+ "SELECT " + KEY_USERNAME + "," + KEY_PASSWORD + " FROM " + TABLE_NAME_FEED_ITEMS
|
||||
+ " INNER JOIN " + TABLE_NAME_FEEDS
|
||||
+ " ON " + TABLE_NAME_FEED_IMAGES + "." + KEY_ID + "=" + TABLE_NAME_FEEDS + "." + KEY_IMAGE
|
||||
+ " WHERE " + TABLE_NAME_FEED_IMAGES + "." + KEY_DOWNLOAD_URL + "=" + downloadUrl
|
||||
+ " UNION SELECT " + KEY_USERNAME + "," + KEY_PASSWORD
|
||||
+ " FROM " + TABLE_NAME_FEED_IMAGES
|
||||
+ " INNER JOIN " + TABLE_NAME_FEED_ITEMS
|
||||
+ " ON " + TABLE_NAME_FEED_IMAGES + "." + KEY_ID + "=" + TABLE_NAME_FEED_ITEMS + "." + KEY_IMAGE
|
||||
+ " INNER JOIN " + TABLE_NAME_FEEDS
|
||||
+ " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + TABLE_NAME_FEEDS + "." + KEY_ID
|
||||
+ " WHERE " + TABLE_NAME_FEED_IMAGES + "." + KEY_DOWNLOAD_URL + "=" + downloadUrl;
|
||||
+ " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + " = " + TABLE_NAME_FEEDS + "." + KEY_ID
|
||||
+ " WHERE " + TABLE_NAME_FEED_ITEMS + "." + KEY_IMAGE_URL + "=" + downloadUrl
|
||||
+ " UNION SELECT " + KEY_USERNAME + "," + KEY_PASSWORD + " FROM " + TABLE_NAME_FEEDS
|
||||
+ " WHERE " + TABLE_NAME_FEEDS + "." + KEY_IMAGE_URL + "=" + downloadUrl;
|
||||
return db.rawQuery(query, null);
|
||||
}
|
||||
|
||||
@ -1672,7 +1586,7 @@ public class PodDBAdapter {
|
||||
*/
|
||||
private static class PodDBHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final int VERSION = 1060200;
|
||||
private static final int VERSION = 1060596;
|
||||
|
||||
private final Context context;
|
||||
|
||||
@ -1693,7 +1607,6 @@ public class PodDBAdapter {
|
||||
public void onCreate(final SQLiteDatabase db) {
|
||||
db.execSQL(CREATE_TABLE_FEEDS);
|
||||
db.execSQL(CREATE_TABLE_FEED_ITEMS);
|
||||
db.execSQL(CREATE_TABLE_FEED_IMAGES);
|
||||
db.execSQL(CREATE_TABLE_FEED_MEDIA);
|
||||
db.execSQL(CREATE_TABLE_DOWNLOAD_LOG);
|
||||
db.execSQL(CREATE_TABLE_QUEUE);
|
||||
@ -1701,7 +1614,6 @@ public class PodDBAdapter {
|
||||
db.execSQL(CREATE_TABLE_FAVORITES);
|
||||
|
||||
db.execSQL(CREATE_INDEX_FEEDITEMS_FEED);
|
||||
db.execSQL(CREATE_INDEX_FEEDITEMS_IMAGE);
|
||||
db.execSQL(CREATE_INDEX_FEEDITEMS_PUBDATE);
|
||||
db.execSQL(CREATE_INDEX_FEEDITEMS_READ);
|
||||
db.execSQL(CREATE_INDEX_FEEDMEDIA_FEEDITEM);
|
||||
@ -1716,263 +1628,7 @@ public class PodDBAdapter {
|
||||
EventBus.getDefault().post(ProgressEvent.start(context.getString(R.string.progress_upgrading_database)));
|
||||
Log.w("DBAdapter", "Upgrading from version " + oldVersion + " to "
|
||||
+ newVersion + ".");
|
||||
if (oldVersion <= 1) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN "
|
||||
+ KEY_TYPE + " TEXT");
|
||||
}
|
||||
if (oldVersion <= 2) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS
|
||||
+ " ADD COLUMN " + KEY_LINK + " TEXT");
|
||||
}
|
||||
if (oldVersion <= 3) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
|
||||
+ " ADD COLUMN " + KEY_ITEM_IDENTIFIER + " TEXT");
|
||||
}
|
||||
if (oldVersion <= 4) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN "
|
||||
+ KEY_FEED_IDENTIFIER + " TEXT");
|
||||
}
|
||||
if (oldVersion <= 5) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_DOWNLOAD_LOG
|
||||
+ " ADD COLUMN " + KEY_REASON_DETAILED + " TEXT");
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_DOWNLOAD_LOG
|
||||
+ " ADD COLUMN " + KEY_DOWNLOADSTATUS_TITLE + " TEXT");
|
||||
}
|
||||
if (oldVersion <= 6) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS
|
||||
+ " ADD COLUMN " + KEY_CHAPTER_TYPE + " INTEGER");
|
||||
}
|
||||
if (oldVersion <= 7) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " ADD COLUMN " + KEY_PLAYBACK_COMPLETION_DATE
|
||||
+ " INTEGER");
|
||||
}
|
||||
if (oldVersion <= 8) {
|
||||
final int KEY_ID_POSITION = 0;
|
||||
final int KEY_MEDIA_POSITION = 1;
|
||||
|
||||
// Add feeditem column to feedmedia table
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " ADD COLUMN " + KEY_FEEDITEM
|
||||
+ " INTEGER");
|
||||
Cursor feeditemCursor = db.query(PodDBAdapter.TABLE_NAME_FEED_ITEMS,
|
||||
new String[]{KEY_ID, KEY_MEDIA}, "? > 0",
|
||||
new String[]{KEY_MEDIA}, null, null, null);
|
||||
if (feeditemCursor.moveToFirst()) {
|
||||
db.beginTransaction();
|
||||
ContentValues contentValues = new ContentValues();
|
||||
do {
|
||||
long mediaId = feeditemCursor.getLong(KEY_MEDIA_POSITION);
|
||||
contentValues.put(KEY_FEEDITEM, feeditemCursor.getLong(KEY_ID_POSITION));
|
||||
db.update(PodDBAdapter.TABLE_NAME_FEED_MEDIA, contentValues, KEY_ID + "=?", new String[]{String.valueOf(mediaId)});
|
||||
contentValues.clear();
|
||||
} while (feeditemCursor.moveToNext());
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
feeditemCursor.close();
|
||||
}
|
||||
if (oldVersion <= 9) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + KEY_AUTO_DOWNLOAD
|
||||
+ " INTEGER DEFAULT 1");
|
||||
}
|
||||
if (oldVersion <= 10) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + KEY_FLATTR_STATUS
|
||||
+ " INTEGER");
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
|
||||
+ " ADD COLUMN " + KEY_FLATTR_STATUS
|
||||
+ " INTEGER");
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " ADD COLUMN " + KEY_PLAYED_DURATION
|
||||
+ " INTEGER");
|
||||
}
|
||||
if (oldVersion <= 11) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + KEY_USERNAME
|
||||
+ " TEXT");
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + KEY_PASSWORD
|
||||
+ " TEXT");
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
|
||||
+ " ADD COLUMN " + KEY_IMAGE
|
||||
+ " INTEGER");
|
||||
}
|
||||
if (oldVersion <= 12) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + KEY_IS_PAGED + " INTEGER DEFAULT 0");
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + KEY_NEXT_PAGE_LINK + " TEXT");
|
||||
}
|
||||
if (oldVersion <= 13) {
|
||||
// remove duplicate rows in "Chapters" table that were created because of a bug.
|
||||
db.execSQL(String.format("DELETE FROM %s WHERE %s NOT IN " +
|
||||
"(SELECT MIN(%s) as %s FROM %s GROUP BY %s,%s,%s,%s,%s)",
|
||||
PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS,
|
||||
KEY_ID,
|
||||
KEY_ID,
|
||||
KEY_ID,
|
||||
PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS,
|
||||
KEY_TITLE,
|
||||
KEY_START,
|
||||
KEY_FEEDITEM,
|
||||
KEY_LINK,
|
||||
KEY_CHAPTER_TYPE));
|
||||
}
|
||||
if (oldVersion <= 14) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
|
||||
+ " ADD COLUMN " + KEY_AUTO_DOWNLOAD + " INTEGER");
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
|
||||
+ " SET " + KEY_AUTO_DOWNLOAD + " = "
|
||||
+ "(SELECT " + KEY_AUTO_DOWNLOAD
|
||||
+ " FROM " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " WHERE " + PodDBAdapter.TABLE_NAME_FEEDS + "." + KEY_ID
|
||||
+ " = " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + ")");
|
||||
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + KEY_HIDE + " TEXT");
|
||||
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + KEY_LAST_UPDATE_FAILED + " INTEGER DEFAULT 0");
|
||||
|
||||
// create indexes
|
||||
db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_FEED);
|
||||
db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_IMAGE);
|
||||
db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDMEDIA_FEEDITEM);
|
||||
db.execSQL(PodDBAdapter.CREATE_INDEX_QUEUE_FEEDITEM);
|
||||
db.execSQL(PodDBAdapter.CREATE_INDEX_SIMPLECHAPTERS_FEEDITEM);
|
||||
}
|
||||
if (oldVersion <= 15) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " ADD COLUMN " + KEY_HAS_EMBEDDED_PICTURE + " INTEGER DEFAULT -1");
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " SET " + KEY_HAS_EMBEDDED_PICTURE + "=0"
|
||||
+ " WHERE " + KEY_DOWNLOADED + "=0");
|
||||
Cursor c = db.rawQuery("SELECT " + KEY_FILE_URL
|
||||
+ " FROM " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " WHERE " + KEY_DOWNLOADED + "=1 "
|
||||
+ " AND " + KEY_HAS_EMBEDDED_PICTURE + "=-1", null);
|
||||
if (c.moveToFirst()) {
|
||||
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
|
||||
do {
|
||||
String fileUrl = c.getString(0);
|
||||
try {
|
||||
mmr.setDataSource(fileUrl);
|
||||
byte[] image = mmr.getEmbeddedPicture();
|
||||
if (image != null) {
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " SET " + KEY_HAS_EMBEDDED_PICTURE + "=1"
|
||||
+ " WHERE " + KEY_FILE_URL + "='" + fileUrl + "'");
|
||||
} else {
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " SET " + KEY_HAS_EMBEDDED_PICTURE + "=0"
|
||||
+ " WHERE " + KEY_FILE_URL + "='" + fileUrl + "'");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} while (c.moveToNext());
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
if (oldVersion <= 16) {
|
||||
String selectNew = "SELECT " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + KEY_ID
|
||||
+ " FROM " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
|
||||
+ " INNER JOIN " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + " ON "
|
||||
+ PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + KEY_ID + "="
|
||||
+ PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + KEY_FEEDITEM
|
||||
+ " LEFT OUTER JOIN " + PodDBAdapter.TABLE_NAME_QUEUE + " ON "
|
||||
+ PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + KEY_ID + "="
|
||||
+ PodDBAdapter.TABLE_NAME_QUEUE + "." + KEY_FEEDITEM
|
||||
+ " WHERE "
|
||||
+ PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + KEY_READ + " = 0 AND " // unplayed
|
||||
+ PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + KEY_DOWNLOADED + " = 0 AND " // undownloaded
|
||||
+ PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + KEY_POSITION + " = 0 AND " // not partially played
|
||||
+ PodDBAdapter.TABLE_NAME_QUEUE + "." + KEY_ID + " IS NULL"; // not in queue
|
||||
String sql = "UPDATE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
|
||||
+ " SET " + KEY_READ + "=" + FeedItem.NEW
|
||||
+ " WHERE " + KEY_ID + " IN (" + selectNew + ")";
|
||||
Log.d("Migration", "SQL: " + sql);
|
||||
db.execSQL(sql);
|
||||
}
|
||||
if (oldVersion <= 17) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_AUTO_DELETE_ACTION + " INTEGER DEFAULT 0");
|
||||
}
|
||||
if (oldVersion < 1030005) {
|
||||
db.execSQL("UPDATE FeedItems SET auto_download=0 WHERE " +
|
||||
"(read=1 OR id IN (SELECT feeditem FROM FeedMedia WHERE position>0 OR downloaded=1)) " +
|
||||
"AND id NOT IN (SELECT feeditem FROM Queue)");
|
||||
}
|
||||
if (oldVersion < 1040001) {
|
||||
db.execSQL(CREATE_TABLE_FAVORITES);
|
||||
}
|
||||
if (oldVersion < 1040002) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_LAST_PLAYED_TIME + " INTEGER DEFAULT 0");
|
||||
}
|
||||
if (oldVersion < 1040013) {
|
||||
db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_PUBDATE);
|
||||
db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_READ);
|
||||
}
|
||||
if (oldVersion < 1050003) {
|
||||
// Migrates feed list filter data
|
||||
|
||||
db.beginTransaction();
|
||||
|
||||
// Change to intermediate values to avoid overwriting in the following find/replace
|
||||
db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'unplayed', 'noplay')");
|
||||
db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'not_queued', 'noqueue')");
|
||||
db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'not_downloaded', 'nodl')");
|
||||
|
||||
// Replace played, queued, and downloaded with their opposites
|
||||
db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'played', 'unplayed')");
|
||||
db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'queued', 'not_queued')");
|
||||
db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'downloaded', 'not_downloaded')");
|
||||
|
||||
// Now replace intermediates for unplayed, not queued, etc. with their opposites
|
||||
db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'noplay', 'played')");
|
||||
db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'noqueue', 'queued')");
|
||||
db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'nodl', 'downloaded')");
|
||||
|
||||
// Paused doesn't have an opposite, so unplayed is the next best option
|
||||
db.execSQL("UPDATE " + TABLE_NAME_FEEDS + "\n" +
|
||||
"SET " + KEY_HIDE + " = replace(" + KEY_HIDE + ", 'paused', 'unplayed')");
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
|
||||
// and now get ready for autodownload filters
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_INCLUDE_FILTER + " TEXT DEFAULT ''");
|
||||
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_EXCLUDE_FILTER + " TEXT DEFAULT ''");
|
||||
|
||||
// and now auto refresh
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_KEEP_UPDATED + " INTEGER DEFAULT 1");
|
||||
}
|
||||
if (oldVersion < 1050004) {
|
||||
// prevent old timestamps to be misinterpreted as ETags
|
||||
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " SET " + PodDBAdapter.KEY_LASTUPDATE + "=NULL");
|
||||
}
|
||||
if (oldVersion < 1060200) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_CUSTOM_TITLE + " TEXT");
|
||||
}
|
||||
|
||||
DBUpgrader.upgrade(db, oldVersion, newVersion);
|
||||
EventBus.getDefault().post(ProgressEvent.end());
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import org.xml.sax.Attributes;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.syndication.handler.HandlerState;
|
||||
|
||||
public class NSITunes extends Namespace {
|
||||
@ -16,7 +15,6 @@ public class NSITunes extends Namespace {
|
||||
public static final String NSURI = "http://www.itunes.com/dtds/podcast-1.0.dtd";
|
||||
|
||||
private static final String IMAGE = "image";
|
||||
private static final String IMAGE_TITLE = "image";
|
||||
private static final String IMAGE_HREF = "href";
|
||||
|
||||
private static final String AUTHOR = "author";
|
||||
@ -29,21 +27,15 @@ public class NSITunes extends Namespace {
|
||||
public SyndElement handleElementStart(String localName, HandlerState state,
|
||||
Attributes attributes) {
|
||||
if (IMAGE.equals(localName)) {
|
||||
FeedImage image = new FeedImage();
|
||||
image.setTitle(IMAGE_TITLE);
|
||||
image.setDownload_url(attributes.getValue(IMAGE_HREF));
|
||||
String url = attributes.getValue(IMAGE_HREF);
|
||||
|
||||
if (state.getCurrentItem() != null) {
|
||||
// this is an items image
|
||||
image.setTitle(state.getCurrentItem().getTitle() + IMAGE_TITLE);
|
||||
image.setOwner(state.getCurrentItem());
|
||||
state.getCurrentItem().setImage(image);
|
||||
state.getCurrentItem().setImageUrl(url);
|
||||
} else {
|
||||
// this is the feed image
|
||||
// prefer to all other images
|
||||
if (!TextUtils.isEmpty(image.getDownload_url())) {
|
||||
image.setOwner(state.getFeed());
|
||||
state.getFeed().setImage(image);
|
||||
if (!TextUtils.isEmpty(url)) {
|
||||
state.getFeed().setImageUrl(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import org.xml.sax.Attributes;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.syndication.handler.HandlerState;
|
||||
import de.danoeh.antennapod.core.syndication.namespace.atom.AtomText;
|
||||
@ -94,25 +93,16 @@ public class NSMedia extends Namespace {
|
||||
}
|
||||
state.getCurrentItem().setMedia(media);
|
||||
} else if (state.getCurrentItem() != null && url != null && validTypeImage) {
|
||||
FeedImage image = new FeedImage();
|
||||
image.setDownload_url(url);
|
||||
image.setOwner(state.getCurrentItem());
|
||||
|
||||
state.getCurrentItem().setImage(image);
|
||||
state.getCurrentItem().setImageUrl(url);
|
||||
}
|
||||
} else if (IMAGE.equals(localName)) {
|
||||
String url = attributes.getValue(IMAGE_URL);
|
||||
if (url != null) {
|
||||
FeedImage image = new FeedImage();
|
||||
image.setDownload_url(url);
|
||||
|
||||
if (state.getCurrentItem() != null) {
|
||||
image.setOwner(state.getCurrentItem());
|
||||
state.getCurrentItem().setImage(image);
|
||||
state.getCurrentItem().setImageUrl(url);
|
||||
} else {
|
||||
if (state.getFeed().getImage() == null) {
|
||||
image.setOwner(state.getFeed());
|
||||
state.getFeed().setImage(image);
|
||||
if (state.getFeed().getImageUrl() == null) {
|
||||
state.getFeed().setImageUrl(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import android.util.Log;
|
||||
import org.xml.sax.Attributes;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.syndication.handler.HandlerState;
|
||||
@ -77,17 +76,6 @@ public class NSRSS20 extends Namespace {
|
||||
state.getCurrentItem().setMedia(media);
|
||||
}
|
||||
|
||||
} else if (IMAGE.equals(localName)) {
|
||||
if (state.getTagstack().size() >= 1) {
|
||||
String parent = state.getTagstack().peek().getName();
|
||||
if (CHANNEL.equals(parent)) {
|
||||
Feed feed = state.getFeed();
|
||||
if(feed != null && feed.getImage() == null) {
|
||||
feed.setImage(new FeedImage());
|
||||
feed.getImage().setOwner(state.getFeed());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new SyndElement(localName, this);
|
||||
}
|
||||
@ -134,11 +122,6 @@ public class NSRSS20 extends Namespace {
|
||||
state.getCurrentItem().setTitle(title);
|
||||
} else if (CHANNEL.equals(second) && state.getFeed() != null) {
|
||||
state.getFeed().setTitle(title);
|
||||
} else if (IMAGE.equals(second) && CHANNEL.equals(third)) {
|
||||
if(state.getFeed() != null && state.getFeed().getImage() != null &&
|
||||
state.getFeed().getImage().getTitle() == null) {
|
||||
state.getFeed().getImage().setTitle(title);
|
||||
}
|
||||
}
|
||||
} else if (LINK.equals(top)) {
|
||||
if (CHANNEL.equals(second) && state.getFeed() != null) {
|
||||
@ -150,9 +133,8 @@ public class NSRSS20 extends Namespace {
|
||||
state.getCurrentItem().setPubDate(DateUtils.parse(content));
|
||||
} else if (URL.equals(top) && IMAGE.equals(second) && CHANNEL.equals(third)) {
|
||||
// prefer itunes:image
|
||||
if(state.getFeed() != null && state.getFeed().getImage() != null &&
|
||||
state.getFeed().getImage().getDownload_url() == null) {
|
||||
state.getFeed().getImage().setDownload_url(content);
|
||||
if (state.getFeed() != null) {
|
||||
state.getFeed().setImageUrl(content);
|
||||
}
|
||||
} else if (DESCR.equals(localName)) {
|
||||
if (CHANNEL.equals(second) && state.getFeed() != null) {
|
||||
|
@ -5,7 +5,6 @@ import android.util.Log;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.syndication.handler.HandlerState;
|
||||
@ -210,10 +209,10 @@ public class NSAtom extends Namespace {
|
||||
state.getCurrentItem().setPubDate(DateUtils.parse(content));
|
||||
} else if (PUBLISHED.equals(top) && ENTRY.equals(second) && state.getCurrentItem() != null) {
|
||||
state.getCurrentItem().setPubDate(DateUtils.parse(content));
|
||||
} else if (IMAGE_LOGO.equals(top) && state.getFeed() != null && state.getFeed().getImage() == null) {
|
||||
state.getFeed().setImage(new FeedImage(state.getFeed(), content, null));
|
||||
} else if (IMAGE_LOGO.equals(top) && state.getFeed() != null && state.getFeed().getImageUrl() == null) {
|
||||
state.getFeed().setImageUrl(content);
|
||||
} else if (IMAGE_ICON.equals(top) && state.getFeed() != null) {
|
||||
state.getFeed().setImage(new FeedImage(state.getFeed(), content, null));
|
||||
state.getFeed().setImageUrl(content);
|
||||
} else if (AUTHOR_NAME.equals(top) && AUTHOR.equals(second) &&
|
||||
state.getFeed() != null && state.getCurrentItem() == null) {
|
||||
String currentName = state.getFeed().getAuthor();
|
||||
|
@ -75,4 +75,18 @@ public class FeedItemUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the link for the feed item for the purpose of Share. It fallbacks to
|
||||
* use the feed's link if the named feed item has no link.
|
||||
*/
|
||||
public static String getLinkWithFallback(FeedItem item) {
|
||||
if (item == null) {
|
||||
return null;
|
||||
} else if (item.getLink() != null) {
|
||||
return item.getLink();
|
||||
} else if (item.getFeed() != null) {
|
||||
return item.getFeed().getLink();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package de.danoeh.antennapod.core.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
|
||||
public class FeedUpdateUtils {
|
||||
private static final String TAG = "FeedUpdateUtils";
|
||||
|
||||
private FeedUpdateUtils() {
|
||||
|
||||
}
|
||||
|
||||
public static void startAutoUpdate(Context context, Runnable callback) {
|
||||
if (NetworkUtils.networkAvailable() && NetworkUtils.isDownloadAllowed()) {
|
||||
DBTasks.refreshAllFeeds(context, null, callback);
|
||||
} else {
|
||||
Log.d(TAG, "Blocking automatic update: no wifi available / no mobile updates allowed");
|
||||
}
|
||||
}
|
||||
}
|
@ -50,11 +50,15 @@ public class ShareUtils {
|
||||
return item.getFeed().getTitle() + ": " + item.getTitle();
|
||||
}
|
||||
|
||||
public static boolean hasLinkToShare(FeedItem item) {
|
||||
return FeedItemUtil.getLinkWithFallback(item) != null;
|
||||
}
|
||||
|
||||
public static void shareFeedItemLink(Context context, FeedItem item, boolean withPosition) {
|
||||
String text = getItemShareText(item) + " " + item.getLink();
|
||||
String text = getItemShareText(item) + " " + FeedItemUtil.getLinkWithFallback(item);
|
||||
if(withPosition) {
|
||||
int pos = item.getMedia().getPosition();
|
||||
text = item.getLink() + " [" + Converter.getDurationStringLong(pos) + "]";
|
||||
text += " [" + Converter.getDurationStringLong(pos) + "]";
|
||||
}
|
||||
shareLink(context, text);
|
||||
}
|
||||
|
@ -1,7 +1,12 @@
|
||||
package de.danoeh.antennapod.core.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.AttrRes;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.util.Log;
|
||||
|
||||
import android.util.TypedValue;
|
||||
import de.danoeh.antennapod.core.R;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
|
||||
@ -12,6 +17,8 @@ public class ThemeUtils {
|
||||
int theme = UserPreferences.getTheme();
|
||||
if (theme == R.style.Theme_AntennaPod_Dark) {
|
||||
return R.color.selection_background_color_dark;
|
||||
} else if (theme == R.style.Theme_AntennaPod_TrueBlack){
|
||||
return R.color.selection_background_color_trueblack;
|
||||
} else if (theme == R.style.Theme_AntennaPod_Light) {
|
||||
return R.color.selection_background_color_light;
|
||||
} else {
|
||||
@ -20,4 +27,10 @@ public class ThemeUtils {
|
||||
return R.color.selection_background_color_light;
|
||||
}
|
||||
}
|
||||
|
||||
public static @ColorInt int getColorFromAttr(Context context, @AttrRes int attr) {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
context.getTheme().resolveAttribute(attr, typedValue, true);
|
||||
return typedValue.data;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,155 @@
|
||||
package de.danoeh.antennapod.core.util.download;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.job.JobInfo;
|
||||
import android.app.job.JobScheduler;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.SystemClock;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.core.receiver.FeedUpdateReceiver;
|
||||
import de.danoeh.antennapod.core.service.FeedUpdateJobService;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class AutoUpdateManager {
|
||||
private static final int JOB_ID_FEED_UPDATE = 42;
|
||||
private static final String TAG = "AutoUpdateManager";
|
||||
|
||||
private AutoUpdateManager() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the interval in which the feeds are refreshed automatically
|
||||
*/
|
||||
public static void restartUpdateIntervalAlarm(Context context, long triggerAtMillis, long intervalMillis) {
|
||||
Log.d(TAG, "Restarting update alarm.");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
restartJobServiceInterval(context, intervalMillis);
|
||||
} else {
|
||||
restartAlarmManagerInterval(context, triggerAtMillis, intervalMillis);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets time of day the feeds are refreshed automatically
|
||||
*/
|
||||
public static void restartUpdateTimeOfDayAlarm(Context context, int hoursOfDay, int minute) {
|
||||
Log.d(TAG, "Restarting update alarm.");
|
||||
|
||||
Calendar now = Calendar.getInstance();
|
||||
Calendar alarm = (Calendar)now.clone();
|
||||
alarm.set(Calendar.HOUR_OF_DAY, hoursOfDay);
|
||||
alarm.set(Calendar.MINUTE, minute);
|
||||
if (alarm.before(now) || alarm.equals(now)) {
|
||||
alarm.add(Calendar.DATE, 1);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
long triggerAtMillis = alarm.getTimeInMillis() - now.getTimeInMillis();
|
||||
restartJobServiceTriggerAt(context, triggerAtMillis);
|
||||
} else {
|
||||
restartAlarmManagerTimeOfDay(context, alarm);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
private static JobInfo.Builder getFeedUpdateJobBuilder(Context context) {
|
||||
ComponentName serviceComponent = new ComponentName(context, FeedUpdateJobService.class);
|
||||
JobInfo.Builder builder = new JobInfo.Builder(JOB_ID_FEED_UPDATE, serviceComponent);
|
||||
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
|
||||
builder.setPersisted(true);
|
||||
return builder;
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
private static void restartJobServiceInterval(Context context, long intervalMillis) {
|
||||
JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
|
||||
if (jobScheduler == null) {
|
||||
Log.d(TAG, "JobScheduler was null.");
|
||||
return;
|
||||
}
|
||||
|
||||
JobInfo oldJob = jobScheduler.getPendingJob(JOB_ID_FEED_UPDATE);
|
||||
if (oldJob != null && oldJob.getIntervalMillis() == intervalMillis) {
|
||||
Log.d(TAG, "JobScheduler was already set at interval " + intervalMillis + ", ignoring.");
|
||||
return;
|
||||
}
|
||||
|
||||
JobInfo.Builder builder = getFeedUpdateJobBuilder(context);
|
||||
builder.setPeriodic(intervalMillis);
|
||||
jobScheduler.cancel(JOB_ID_FEED_UPDATE);
|
||||
|
||||
if (intervalMillis <= 0) {
|
||||
Log.d(TAG, "Automatic update was deactivated");
|
||||
return;
|
||||
}
|
||||
|
||||
jobScheduler.schedule(builder.build());
|
||||
Log.d(TAG, "JobScheduler was set at interval " + intervalMillis);
|
||||
}
|
||||
|
||||
private static void restartAlarmManagerInterval(Context context, long triggerAtMillis, long intervalMillis) {
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
|
||||
if (alarmManager == null) {
|
||||
Log.d(TAG, "AlarmManager was null");
|
||||
return;
|
||||
}
|
||||
|
||||
PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0,
|
||||
new Intent(context, FeedUpdateReceiver.class), 0);
|
||||
alarmManager.cancel(updateIntent);
|
||||
|
||||
if (intervalMillis <= 0) {
|
||||
Log.d(TAG, "Automatic update was deactivated");
|
||||
return;
|
||||
}
|
||||
|
||||
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime() + triggerAtMillis,
|
||||
updateIntent);
|
||||
Log.d(TAG, "Changed alarm to new interval " + TimeUnit.MILLISECONDS.toHours(intervalMillis) + " h");
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
private static void restartJobServiceTriggerAt(Context context, long triggerAtMillis) {
|
||||
JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
|
||||
if (jobScheduler == null) {
|
||||
Log.d(TAG, "JobScheduler was null.");
|
||||
return;
|
||||
}
|
||||
|
||||
JobInfo.Builder builder = getFeedUpdateJobBuilder(context);
|
||||
builder.setMinimumLatency(triggerAtMillis);
|
||||
jobScheduler.cancel(JOB_ID_FEED_UPDATE);
|
||||
jobScheduler.schedule(builder.build());
|
||||
Log.d(TAG, "JobScheduler was set for " + triggerAtMillis);
|
||||
}
|
||||
|
||||
private static void restartAlarmManagerTimeOfDay(Context context, Calendar alarm) {
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
|
||||
if (alarmManager == null) {
|
||||
Log.d(TAG, "AlarmManager was null");
|
||||
return;
|
||||
}
|
||||
|
||||
PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0,
|
||||
new Intent(context, FeedUpdateReceiver.class), 0);
|
||||
alarmManager.cancel(updateIntent);
|
||||
|
||||
Log.d(TAG, "Alarm set for: " + alarm.toString() + " : " + alarm.getTimeInMillis());
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP,
|
||||
alarm.getTimeInMillis(),
|
||||
updateIntent);
|
||||
Log.d(TAG, "Changed alarm to new time of day " + alarm.get(Calendar.HOUR_OF_DAY) + ":" + alarm.get(Calendar.MINUTE));
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package de.danoeh.antennapod.core.util.gui;
|
||||
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import de.danoeh.antennapod.core.R;
|
||||
|
||||
public class NotificationUtils {
|
||||
public static final String CHANNEL_ID_USER_ACTION = "user_action";
|
||||
public static final String CHANNEL_ID_DOWNLOADING = "downloading";
|
||||
public static final String CHANNEL_ID_PLAYING = "playing";
|
||||
public static final String CHANNEL_ID_ERROR = "error";
|
||||
|
||||
public static void createChannels(Context context) {
|
||||
if (android.os.Build.VERSION.SDK_INT < 26) {
|
||||
return;
|
||||
}
|
||||
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
if (mNotificationManager != null) {
|
||||
mNotificationManager.createNotificationChannel(createChannelUserAction(context));
|
||||
mNotificationManager.createNotificationChannel(createChannelDownloading(context));
|
||||
mNotificationManager.createNotificationChannel(createChannelPlaying(context));
|
||||
mNotificationManager.createNotificationChannel(createChannelError(context));
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
private static NotificationChannel createChannelUserAction(Context c) {
|
||||
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_USER_ACTION,
|
||||
c.getString(R.string.notification_channel_user_action), NotificationManager.IMPORTANCE_HIGH);
|
||||
mChannel.setDescription(c.getString(R.string.notification_channel_user_action_description));
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
private static NotificationChannel createChannelDownloading(Context c) {
|
||||
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_DOWNLOADING,
|
||||
c.getString(R.string.notification_channel_downloading), NotificationManager.IMPORTANCE_LOW);
|
||||
mChannel.setDescription(c.getString(R.string.notification_channel_downloading_description));
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
private static NotificationChannel createChannelPlaying(Context c) {
|
||||
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_PLAYING,
|
||||
c.getString(R.string.notification_channel_playing), NotificationManager.IMPORTANCE_LOW);
|
||||
mChannel.setDescription(c.getString(R.string.notification_channel_playing_description));
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
private static NotificationChannel createChannelError(Context c) {
|
||||
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_ERROR,
|
||||
c.getString(R.string.notification_channel_error), NotificationManager.IMPORTANCE_HIGH);
|
||||
mChannel.setDescription(c.getString(R.string.notification_channel_error_description));
|
||||
return mChannel;
|
||||
}
|
||||
}
|
@ -3,6 +3,8 @@ package de.danoeh.antennapod.core.util.playback;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Parcelable;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
@ -11,6 +13,7 @@ import de.danoeh.antennapod.core.asynctask.ImageResource;
|
||||
import de.danoeh.antennapod.core.feed.Chapter;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.feed.MediaType;
|
||||
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.util.ShownotesProvider;
|
||||
|
||||
@ -175,6 +178,23 @@ public interface Playable extends Parcelable,
|
||||
class PlayableUtils {
|
||||
private static final String TAG = "PlayableUtils";
|
||||
|
||||
/**
|
||||
* Restores a playable object from a sharedPreferences file. This method might load data from the database,
|
||||
* depending on the type of playable that was restored.
|
||||
*
|
||||
* @return The restored Playable object
|
||||
*/
|
||||
@Nullable
|
||||
public static Playable createInstanceFromPreferences(Context context) {
|
||||
long currentlyPlayingMedia = PlaybackPreferences.getCurrentlyPlayingMedia();
|
||||
if (currentlyPlayingMedia != PlaybackPreferences.NO_MEDIA_PLAYING) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
|
||||
return PlayableUtils.createInstanceFromPreferences(context,
|
||||
(int) currentlyPlayingMedia, prefs);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores a playable object from a sharedPreferences file. This method might load data from the database,
|
||||
* depending on the type of playable that was restored.
|
||||
|
@ -14,6 +14,8 @@ import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
@ -59,7 +61,7 @@ public abstract class PlaybackController {
|
||||
|
||||
private PlaybackService playbackService;
|
||||
private Playable media;
|
||||
private PlayerStatus status;
|
||||
private PlayerStatus status = PlayerStatus.STOPPED;
|
||||
|
||||
private final ScheduledThreadPoolExecutor schedExecutor;
|
||||
private static final int SCHED_EX_POOLSIZE = 1;
|
||||
@ -69,6 +71,7 @@ public abstract class PlaybackController {
|
||||
|
||||
private boolean mediaInfoLoaded = false;
|
||||
private boolean released = false;
|
||||
private boolean initialized = false;
|
||||
|
||||
private Subscription serviceBinder;
|
||||
|
||||
@ -92,10 +95,22 @@ public abstract class PlaybackController {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new connection to the playbackService. Should be called in the
|
||||
* activity's onResume() method.
|
||||
* Creates a new connection to the playbackService.
|
||||
*/
|
||||
public void init() {
|
||||
if (PlaybackService.isRunning) {
|
||||
initServiceRunning();
|
||||
} else {
|
||||
initServiceNotRunning();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void initServiceRunning() {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
|
||||
activity.registerReceiver(statusUpdate, new IntentFilter(
|
||||
PlaybackService.ACTION_PLAYER_STATUS_CHANGED));
|
||||
|
||||
@ -167,7 +182,7 @@ public abstract class PlaybackController {
|
||||
*/
|
||||
private void bindToService() {
|
||||
Log.d(TAG, "Trying to connect to service");
|
||||
if(serviceBinder != null) {
|
||||
if (serviceBinder != null) {
|
||||
serviceBinder.unsubscribe();
|
||||
}
|
||||
serviceBinder = Observable.fromCallable(this::getPlayLastPlayedMediaIntent)
|
||||
@ -178,7 +193,7 @@ public abstract class PlaybackController {
|
||||
if (!PlaybackService.started) {
|
||||
if (intent != null) {
|
||||
Log.d(TAG, "Calling start service");
|
||||
activity.startService(intent);
|
||||
ContextCompat.startForegroundService(activity, intent);
|
||||
bound = activity.bindService(intent, mConnection, 0);
|
||||
} else {
|
||||
status = PlayerStatus.STOPPED;
|
||||
@ -198,31 +213,24 @@ public abstract class PlaybackController {
|
||||
* Returns an intent that starts the PlaybackService and plays the last
|
||||
* played media or null if no last played media could be found.
|
||||
*/
|
||||
private Intent getPlayLastPlayedMediaIntent() {
|
||||
@Nullable private Intent getPlayLastPlayedMediaIntent() {
|
||||
Log.d(TAG, "Trying to restore last played media");
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
|
||||
activity.getApplicationContext());
|
||||
long currentlyPlayingMedia = PlaybackPreferences.getCurrentlyPlayingMedia();
|
||||
if (currentlyPlayingMedia != PlaybackPreferences.NO_MEDIA_PLAYING) {
|
||||
Playable media = PlayableUtils.createInstanceFromPreferences(activity,
|
||||
(int) currentlyPlayingMedia, prefs);
|
||||
if (media != null) {
|
||||
Intent serviceIntent = new Intent(activity, PlaybackService.class);
|
||||
serviceIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media);
|
||||
serviceIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED, false);
|
||||
serviceIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY, true);
|
||||
boolean fileExists = media.localFileAvailable();
|
||||
boolean lastIsStream = PlaybackPreferences.getCurrentEpisodeIsStream();
|
||||
if (!fileExists && !lastIsStream && media instanceof FeedMedia) {
|
||||
DBTasks.notifyMissingFeedMediaFile(activity, (FeedMedia) media);
|
||||
}
|
||||
serviceIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM,
|
||||
lastIsStream || !fileExists);
|
||||
return serviceIntent;
|
||||
}
|
||||
Playable media = PlayableUtils.createInstanceFromPreferences(activity);
|
||||
if (media == null) {
|
||||
Log.d(TAG, "No last played media found");
|
||||
return null;
|
||||
}
|
||||
Log.d(TAG, "No last played media found");
|
||||
return null;
|
||||
|
||||
boolean fileExists = media.localFileAvailable();
|
||||
boolean lastIsStream = PlaybackPreferences.getCurrentEpisodeIsStream();
|
||||
if (!fileExists && !lastIsStream && media instanceof FeedMedia) {
|
||||
DBTasks.notifyMissingFeedMediaFile(activity, (FeedMedia) media);
|
||||
}
|
||||
|
||||
return new PlaybackServiceStarter(activity, media)
|
||||
.startWhenPrepared(false)
|
||||
.shouldStream(lastIsStream || !fileExists)
|
||||
.getIntent();
|
||||
}
|
||||
|
||||
|
||||
@ -511,7 +519,7 @@ public abstract class PlaybackController {
|
||||
"PlaybackService has no media object. Trying to restore last played media.");
|
||||
Intent serviceIntent = getPlayLastPlayedMediaIntent();
|
||||
if (serviceIntent != null) {
|
||||
activity.startService(serviceIntent);
|
||||
ContextCompat.startForegroundService(activity, serviceIntent);
|
||||
}
|
||||
}
|
||||
*/
|
||||
@ -576,6 +584,10 @@ public abstract class PlaybackController {
|
||||
|
||||
public void playPause() {
|
||||
if (playbackService == null) {
|
||||
new PlaybackServiceStarter(activity, media)
|
||||
.startWhenPrepared(true)
|
||||
.streamIfLastWasStream()
|
||||
.start();
|
||||
Log.w(TAG, "Play/Pause button was pressed, but playbackservice was null!");
|
||||
return;
|
||||
}
|
||||
@ -609,6 +621,8 @@ public abstract class PlaybackController {
|
||||
public int getPosition() {
|
||||
if (playbackService != null) {
|
||||
return playbackService.getCurrentPosition();
|
||||
} else if (media != null) {
|
||||
return media.getPosition();
|
||||
} else {
|
||||
return PlaybackService.INVALID_TIME;
|
||||
}
|
||||
@ -617,12 +631,17 @@ public abstract class PlaybackController {
|
||||
public int getDuration() {
|
||||
if (playbackService != null) {
|
||||
return playbackService.getDuration();
|
||||
} else if (media != null) {
|
||||
return media.getDuration();
|
||||
} else {
|
||||
return PlaybackService.INVALID_TIME;
|
||||
}
|
||||
}
|
||||
|
||||
public Playable getMedia() {
|
||||
if (media == null) {
|
||||
media = PlayableUtils.createInstanceFromPreferences(activity);
|
||||
}
|
||||
return media;
|
||||
}
|
||||
|
||||
@ -714,8 +733,13 @@ public abstract class PlaybackController {
|
||||
}
|
||||
|
||||
public boolean isPlayingVideoLocally() {
|
||||
return playbackService != null && PlaybackService.getCurrentMediaType() == MediaType.VIDEO
|
||||
&& !PlaybackService.isCasting();
|
||||
if (PlaybackService.isCasting()) {
|
||||
return false;
|
||||
} else if (playbackService != null) {
|
||||
return PlaybackService.getCurrentMediaType() == MediaType.VIDEO;
|
||||
} else {
|
||||
return getMedia() != null && getMedia().getMediaType() == MediaType.VIDEO;
|
||||
}
|
||||
}
|
||||
|
||||
public Pair<Integer, Integer> getVideoSize() {
|
||||
@ -755,6 +779,21 @@ public abstract class PlaybackController {
|
||||
}
|
||||
}
|
||||
|
||||
private void initServiceNotRunning() {
|
||||
if (getMedia() == null) {
|
||||
return;
|
||||
}
|
||||
if (getMedia().getMediaType() == MediaType.AUDIO) {
|
||||
TypedArray res = activity.obtainStyledAttributes(new int[]{
|
||||
de.danoeh.antennapod.core.R.attr.av_play_big});
|
||||
getPlayButton().setImageResource(
|
||||
res.getResourceId(0, de.danoeh.antennapod.core.R.drawable.ic_play_arrow_grey600_36dp));
|
||||
res.recycle();
|
||||
} else {
|
||||
getPlayButton().setImageResource(R.drawable.ic_av_play_circle_outline_80dp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the current position of the media file that is playing.
|
||||
*/
|
||||
|
@ -0,0 +1,76 @@
|
||||
package de.danoeh.antennapod.core.util.playback;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.MediaPlayer;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
|
||||
public class PlaybackServiceStarter {
|
||||
private final Context context;
|
||||
private final Playable media;
|
||||
private boolean startWhenPrepared = false;
|
||||
private boolean shouldStream = false;
|
||||
private boolean callEvenIfRunning = false;
|
||||
private boolean prepareImmediately = true;
|
||||
|
||||
public PlaybackServiceStarter(Context context, Playable media) {
|
||||
this.context = context;
|
||||
this.media = media;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default value: false
|
||||
*/
|
||||
public PlaybackServiceStarter shouldStream(boolean shouldStream) {
|
||||
this.shouldStream = shouldStream;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PlaybackServiceStarter streamIfLastWasStream() {
|
||||
boolean lastIsStream = PlaybackPreferences.getCurrentEpisodeIsStream();
|
||||
return shouldStream(lastIsStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default value: false
|
||||
*/
|
||||
public PlaybackServiceStarter startWhenPrepared(boolean startWhenPrepared) {
|
||||
this.startWhenPrepared = startWhenPrepared;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default value: false
|
||||
*/
|
||||
public PlaybackServiceStarter callEvenIfRunning(boolean callEvenIfRunning) {
|
||||
this.callEvenIfRunning = callEvenIfRunning;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default value: true
|
||||
*/
|
||||
public PlaybackServiceStarter prepareImmediately(boolean prepareImmediately) {
|
||||
this.prepareImmediately = prepareImmediately;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Intent getIntent() {
|
||||
Intent launchIntent = new Intent(context, PlaybackService.class);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED, startWhenPrepared);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, shouldStream);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY, prepareImmediately);
|
||||
|
||||
return launchIntent;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (PlaybackService.isRunning && !callEvenIfRunning) {
|
||||
return;
|
||||
}
|
||||
ContextCompat.startForegroundService(context, getIntent());
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@android:id/background">
|
||||
<shape>
|
||||
<solid android:color="#000000"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item android:id="@android:id/progress">
|
||||
<clip>
|
||||
<shape>
|
||||
<solid android:color="@color/holo_blue_dark"/>
|
||||
</shape>
|
||||
</clip>
|
||||
</item>
|
||||
</layer-list>
|
@ -6,6 +6,19 @@
|
||||
<style name="Theme.AntennaPod.Dark" parent="Theme.Base.AntennaPod.Dark">
|
||||
<item name="android:windowContentTransitions">true</item>
|
||||
</style>
|
||||
<style name="Theme.AntennaPod.TrueBlack" parent="Theme.Base.AntennaPod.TrueBlack">
|
||||
<item name="android:windowContentTransitions">true</item>
|
||||
<item name="android:navigationBarColor">@color/black</item>
|
||||
<item name="android:colorAccent">@color/white</item>
|
||||
<item name="android:colorPrimary">@color/black</item>
|
||||
<item name="android:colorPrimaryDark">@color/black</item>
|
||||
</style>
|
||||
<style name="Theme.AntennaPod.TrueBlack.NoTitle" parent="Theme.Base.AntennaPod.TrueBlack.NoTitle">
|
||||
<item name="android:navigationBarColor">@color/black</item>
|
||||
<item name="android:colorAccent">@color/white</item>
|
||||
<item name="android:colorPrimary">@color/black</item>
|
||||
<item name="android:colorPrimaryDark">@color/black</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.AntennaPod.Button" parent="Widget.AppCompat.Button">
|
||||
<item name="textAllCaps">true</item>
|
||||
|
@ -137,10 +137,12 @@
|
||||
<string-array name="theme_options">
|
||||
<item>@string/pref_theme_title_light</item>
|
||||
<item>@string/pref_theme_title_dark</item>
|
||||
<item>@string/pref_theme_title_trueblack</item>
|
||||
</string-array>
|
||||
<string-array name="theme_values">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="nav_drawer_titles">
|
||||
|
@ -56,6 +56,7 @@
|
||||
<attr name="ic_cast_disconnect" format="reference"/>
|
||||
<attr name="ic_swap" format="reference"/>
|
||||
<attr name="master_switch_background" format="color"/>
|
||||
<attr name="currently_playing_background" format="color"/>
|
||||
|
||||
<!-- Used in itemdescription -->
|
||||
<attr name="non_transparent_background" format="reference"/>
|
||||
|
@ -22,6 +22,7 @@
|
||||
<color name="image_readability_tint">#80000000</color>
|
||||
<color name="feed_image_bg">#50000000</color>
|
||||
|
||||
<color name="selection_background_color_trueblack">#286E8A</color>
|
||||
<color name="selection_background_color_dark">#286E8A</color>
|
||||
<color name="selection_background_color_light">#81CFEA</color>
|
||||
|
||||
@ -30,6 +31,7 @@
|
||||
|
||||
<color name="highlight_light">#DDDDDD</color>
|
||||
<color name="highlight_dark">#414141</color>
|
||||
<color name="highlight_trueblack">#000000</color>
|
||||
|
||||
<color name="antennapod_blue">#147BAF</color>
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
<!-- Activitiy and fragment titles -->
|
||||
<string name="app_name" translate="false">AntennaPod</string>
|
||||
<string name="provider_authority" translate="false">de.danoeh.antennapod.provider</string>
|
||||
<string name="feed_update_receiver_name">Update Subscriptions</string>
|
||||
<string name="feeds_label">Feeds</string>
|
||||
<string name="statistics_label">Statistics</string>
|
||||
<string name="add_feed_label">Add Podcast</string>
|
||||
@ -29,6 +30,7 @@
|
||||
<string name="free_space_label">%1$s free</string>
|
||||
<string name="episode_cache_full_title">Episode cache full</string>
|
||||
<string name="episode_cache_full_message">The episode cache limit has been reached. You can increase the cache size in the Settings.</string>
|
||||
<string name="synchronizing">Synchronizing…</string>
|
||||
|
||||
<!-- Statistics fragment -->
|
||||
<string name="total_time_listened_to_podcasts">Total time of podcasts played:</string>
|
||||
@ -393,6 +395,7 @@
|
||||
<string name="pref_episode_cache_title">Episode Cache</string>
|
||||
<string name="pref_theme_title_light">Light</string>
|
||||
<string name="pref_theme_title_dark">Dark</string>
|
||||
<string name="pref_theme_title_trueblack">True Black</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>
|
||||
@ -709,4 +712,14 @@
|
||||
<string name="cast_failed_seek">Failed to seek to the new position on the cast device</string>
|
||||
<string name="cast_failed_receiver_player_error">Receiver player has encountered a severe error</string>
|
||||
<string name="cast_failed_media_error_skipping">Error playing media. Skipping…</string>
|
||||
|
||||
<!-- Notification channels -->
|
||||
<string name="notification_channel_user_action">Action required</string>
|
||||
<string name="notification_channel_user_action_description">Shown if your action is required, for example if you need to enter a password.</string>
|
||||
<string name="notification_channel_downloading">Downloading</string>
|
||||
<string name="notification_channel_downloading_description">Shown while currently downloading.</string>
|
||||
<string name="notification_channel_playing">Currently playing</string>
|
||||
<string name="notification_channel_playing_description">Allows to control playback. This is the main notification you see while playing a podcast.</string>
|
||||
<string name="notification_channel_error">Errors</string>
|
||||
<string name="notification_channel_error_description">Shown if something went wrong, for example if download or gpodder sync fails.</string>
|
||||
</resources>
|
||||
|
@ -67,6 +67,8 @@
|
||||
<item type="attr" name="ic_create_new_folder">@drawable/ic_create_new_folder_grey600_24dp</item>
|
||||
<item type="attr" name="ic_cast_disconnect">@drawable/ic_cast_disconnect_grey600_36dp</item>
|
||||
<item type="attr" name="master_switch_background">@color/master_switch_background_light</item>
|
||||
<item type="attr" name="currently_playing_background">@color/highlight_light</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.AntennaPod.Dark" parent="Theme.Base.AntennaPod.Dark">
|
||||
@ -135,8 +137,31 @@
|
||||
<item type="attr" name="ic_create_new_folder">@drawable/ic_create_new_folder_white_24dp</item>
|
||||
<item type="attr" name="ic_cast_disconnect">@drawable/ic_cast_disconnect_white_36dp</item>
|
||||
<item type="attr" name="master_switch_background">@color/master_switch_background_dark</item>
|
||||
<item type="attr" name="currently_playing_background">@color/highlight_dark</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.AntennaPod.TrueBlack" parent="Theme.Base.AntennaPod.TrueBlack">
|
||||
<!-- Room for API dependent attributes -->
|
||||
</style>
|
||||
|
||||
<style name="Theme.Base.AntennaPod.TrueBlack" parent="Theme.Base.AntennaPod.Dark">
|
||||
<item name="progressBarTheme">@style/ProgressBarTrueBlack</item>
|
||||
<item type="attr" name="non_transparent_background">@color/black</item>
|
||||
<item type="attr" name="overlay_background">@color/overlay_dark</item>
|
||||
<item type="attr" name="overlay_drawable">@drawable/overlay_drawable_dark</item>
|
||||
<item type="attr" name="dragview_background">@drawable/ic_drag_vertical_white_48dp</item>
|
||||
<item type="attr" name="dragview_float_background">@color/black</item>
|
||||
<item type="attr" name="nav_drawer_background">@color/black</item>
|
||||
<item name="android:textColorPrimary">@color/white</item>
|
||||
<item name="android:color">@color/white</item>
|
||||
<item name="android:windowBackground">@color/black</item>
|
||||
<item name="android:actionBarStyle">@color/black</item>
|
||||
<item name="colorPrimary">@color/black</item>
|
||||
<item name="colorPrimaryDark">@color/black</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="Theme.AntennaPod.Light.NoTitle" parent="Theme.Base.AntennaPod.Light.NoTitle">
|
||||
<!-- Room for API dependent attributes -->
|
||||
</style>
|
||||
@ -204,6 +229,8 @@
|
||||
<item type="attr" name="ic_create_new_folder">@drawable/ic_create_new_folder_grey600_24dp</item>
|
||||
<item type="attr" name="ic_cast_disconnect">@drawable/ic_cast_disconnect_grey600_36dp</item>
|
||||
<item type="attr" name="master_switch_background">@color/master_switch_background_light</item>
|
||||
<item type="attr" name="currently_playing_background">@color/highlight_light</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.AntennaPod.Dark.NoTitle" parent="Theme.Base.AntennaPod.Dark.NoTitle">
|
||||
@ -273,8 +300,32 @@
|
||||
<item type="attr" name="ic_create_new_folder">@drawable/ic_create_new_folder_white_24dp</item>
|
||||
<item type="attr" name="ic_cast_disconnect">@drawable/ic_cast_disconnect_white_36dp</item>
|
||||
<item type="attr" name="master_switch_background">@color/master_switch_background_dark</item>
|
||||
<item type="attr" name="currently_playing_background">@color/highlight_dark</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.AntennaPod.TrueBlack.NoTitle" parent="Theme.Base.AntennaPod.TrueBlack.NoTitle">
|
||||
<!-- Room for API dependent attributes -->
|
||||
</style>
|
||||
|
||||
<style name="Theme.Base.AntennaPod.TrueBlack.NoTitle" parent="Theme.Base.AntennaPod.Dark.NoTitle">
|
||||
<item name="progressBarTheme">@style/ProgressBarTrueBlack</item>
|
||||
<item type="attr" name="non_transparent_background">@color/black</item>
|
||||
<item type="attr" name="overlay_background">@color/black</item>
|
||||
<item type="attr" name="overlay_drawable">@drawable/overlay_drawable_dark</item>
|
||||
<item type="attr" name="dragview_background">@drawable/ic_drag_vertical_white_48dp</item>
|
||||
<item type="attr" name="dragview_float_background">@color/black</item>
|
||||
<item type="attr" name="nav_drawer_background">@color/black</item>
|
||||
<item type="attr" name="currently_playing_background">@color/highlight_trueblack</item>
|
||||
<item name="android:textColorPrimary">@color/white</item>
|
||||
<item name="android:color">@color/white</item>
|
||||
<item name="android:windowBackground">@color/black</item>
|
||||
<item name="android:actionBarStyle">@color/black</item>
|
||||
<item name="colorPrimary">@color/black</item>
|
||||
<item name="colorPrimaryDark">@color/black</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="Theme.AntennaPod.Dark.Splash" parent="Theme.AppCompat.NoActionBar">
|
||||
<item name="android:windowBackground">@drawable/bg_splash</item>
|
||||
</style>
|
||||
@ -362,4 +413,9 @@
|
||||
<item name="android:progressDrawable">@drawable/progress_bar_horizontal_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="ProgressBarTrueBlack">
|
||||
<item name="android:indeterminateOnly">false</item>
|
||||
<item name="android:progressDrawable">@drawable/progress_bar_horizontal_trueblack</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
@ -13,7 +13,6 @@ import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
@ -97,9 +96,9 @@ public class CastUtils {
|
||||
if (subtitle != null) {
|
||||
metadata.putString(MediaMetadata.KEY_SUBTITLE, subtitle);
|
||||
}
|
||||
FeedImage image = feedItem.getImage();
|
||||
if (image != null && !TextUtils.isEmpty(image.getDownload_url())) {
|
||||
metadata.addImage(new WebImage(Uri.parse(image.getDownload_url())));
|
||||
|
||||
if (!TextUtils.isEmpty(feedItem.getImageUrl())) {
|
||||
metadata.addImage(new WebImage(Uri.parse(feedItem.getImageUrl())));
|
||||
}
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(media.getItem().getPubDate());
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user