Merge branch 'develop' into exo-player

This commit is contained in:
ByteHamster 2018-06-08 20:14:57 +02:00
commit 83a9df2657
52 changed files with 925 additions and 1123 deletions

View File

@ -21,7 +21,7 @@ jobs:
- v1-android-
- run:
command: ./gradlew assembleDebug -PdisablePreDex
command: ./gradlew assembleDebug :core:testPlayDebugUnitTest -PdisablePreDex
no_output_timeout: 1800
- store_artifacts:

View File

@ -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<>());

View File

@ -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);

View File

@ -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);

View File

@ -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()) {

View File

@ -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()) {

View File

@ -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:

View File

@ -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)

View File

@ -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);
}

View File

@ -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));

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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()) {

View File

@ -185,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);
}

View File

@ -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);

View File

@ -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 {
@ -80,6 +80,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 {

View File

@ -1,4 +1,4 @@
package de.danoeh.antennapod.core.tests;
package de.danoeh.antennapod.core;
import android.test.InstrumentationTestRunner;
import android.test.suitebuilder.TestSuiteBuilder;

View File

@ -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);
}
}

View File

@ -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());
}
}
}

View File

@ -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"));

View File

@ -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();

View File

@ -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() {

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -161,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;
}
@ -597,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;
}

View File

@ -55,7 +55,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;
@ -489,9 +488,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++;
}
}
@ -688,10 +685,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 {
@ -1101,26 +1094,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) {

View File

@ -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();

View File

@ -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.
*

View File

@ -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);
}
}
}

View File

@ -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<>();
@ -200,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();
@ -785,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
*/

View File

@ -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());
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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) {

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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">

View File

@ -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"/>

View File

@ -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>

View File

@ -395,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>

View File

@ -67,6 +67,7 @@
<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>
@ -136,9 +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>
@ -206,6 +229,7 @@
<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>
@ -276,9 +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>
@ -366,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>

View File

@ -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());

View File

@ -0,0 +1,32 @@
package android.text;
/**
* A slim-down version of standard {@link android.text.TextUtils} to be used in unit tests.
*/
public class TextUtils {
/**
* Returns true if a and b are equal, including if they are both null.
* <p><i>Note: In platform versions 1.1 and earlier, this method only worked well if
* both the arguments were instances of String.</i></p>
* @param a first CharSequence to check
* @param b second CharSequence to check
* @return true if a and b are equal
*/
public static boolean equals(CharSequence a, CharSequence b) {
if (a == b) return true;
int length;
if (a != null && b != null && (length = a.length()) == b.length()) {
if (a instanceof String && b instanceof String) {
return a.equals(b);
} else {
for (int i = 0; i < length; i++) {
if (a.charAt(i) != b.charAt(i)) return false;
}
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,245 @@
package android.util;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* A stub for {@link android.util.Log} to be used in unit tests.
*
* It outputs the log statements to standard error.
*/
public final class Log {
/**
* Priority constant for the println method; use Log.v.
*/
public static final int VERBOSE = 2;
/**
* Priority constant for the println method; use Log.d.
*/
public static final int DEBUG = 3;
/**
* Priority constant for the println method; use Log.i.
*/
public static final int INFO = 4;
/**
* Priority constant for the println method; use Log.w.
*/
public static final int WARN = 5;
/**
* Priority constant for the println method; use Log.e.
*/
public static final int ERROR = 6;
/**
* Priority constant for the println method.
*/
public static final int ASSERT = 7;
private Log() {
}
/**
* Send a {@link #VERBOSE} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static int v(String tag, String msg) {
return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
}
/**
* Send a {@link #VERBOSE} log message and log the exception.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
* @param tr An exception to log
*/
public static int v(String tag, String msg, Throwable tr) {
return printlns(LOG_ID_MAIN, VERBOSE, tag, msg, tr);
}
/**
* Send a {@link #DEBUG} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static int d(String tag, String msg) {
return println_native(LOG_ID_MAIN, DEBUG, tag, msg);
}
/**
* Send a {@link #DEBUG} log message and log the exception.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
* @param tr An exception to log
*/
public static int d(String tag, String msg, Throwable tr) {
return printlns(LOG_ID_MAIN, DEBUG, tag, msg, tr);
}
/**
* Send an {@link #INFO} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static int i(String tag, String msg) {
return println_native(LOG_ID_MAIN, INFO, tag, msg);
}
/**
* Send a {@link #INFO} log message and log the exception.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
* @param tr An exception to log
*/
public static int i(String tag, String msg, Throwable tr) {
return printlns(LOG_ID_MAIN, INFO, tag, msg, tr);
}
/**
* Send a {@link #WARN} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static int w(String tag, String msg) {
return println_native(LOG_ID_MAIN, WARN, tag, msg);
}
/**
* Send a {@link #WARN} log message and log the exception.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
* @param tr An exception to log
*/
public static int w(String tag, String msg, Throwable tr) {
return printlns(LOG_ID_MAIN, WARN, tag, msg, tr);
}
/**
* Checks to see whether or not a log for the specified tag is loggable at the specified level.
*
* @return true in all cases (for unit test environment)
*/
public static boolean isLoggable(String tag, int level) {
return true;
}
/*
* Send a {@link #WARN} log message and log the exception.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param tr An exception to log
*/
public static int w(String tag, Throwable tr) {
return printlns(LOG_ID_MAIN, WARN, tag, "", tr);
}
/**
* Send an {@link #ERROR} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static int e(String tag, String msg) {
return println_native(LOG_ID_MAIN, ERROR, tag, msg);
}
/**
* Send a {@link #ERROR} log message and log the exception.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
* @param tr An exception to log
*/
public static int e(String tag, String msg, Throwable tr) {
return printlns(LOG_ID_MAIN, ERROR, tag, msg, tr);
}
/**
* What a Terrible Failure: Report a condition that should never happen.
* The error will always be logged at level ASSERT with the call stack.
* Depending on system configuration, a report may be added to the
* {@link android.os.DropBoxManager} and/or the process may be terminated
* immediately with an error dialog.
* @param tag Used to identify the source of a log message.
* @param msg The message you would like logged.
*/
public static int wtf(String tag, String msg) {
return wtf(LOG_ID_MAIN, tag, msg, null, false, false);
}
/**
* Like {@link #wtf(String, String)}, but also writes to the log the full
* call stack.
* @hide
*/
public static int wtfStack(String tag, String msg) {
return wtf(LOG_ID_MAIN, tag, msg, null, true, false);
}
/**
* What a Terrible Failure: Report an exception that should never happen.
* Similar to {@link #wtf(String, String)}, with an exception to log.
* @param tag Used to identify the source of a log message.
* @param tr An exception to log.
*/
public static int wtf(String tag, Throwable tr) {
return wtf(LOG_ID_MAIN, tag, tr.getMessage(), tr, false, false);
}
/**
* What a Terrible Failure: Report an exception that should never happen.
* Similar to {@link #wtf(String, Throwable)}, with a message as well.
* @param tag Used to identify the source of a log message.
* @param msg The message you would like logged.
* @param tr An exception to log. May be null.
*/
public static int wtf(String tag, String msg, Throwable tr) {
return wtf(LOG_ID_MAIN, tag, msg, tr, false, false);
}
/**
* Priority Constant for wtf.
* Added for this custom Log implementation, not in android sources.
*/
private static final int WTF = 8;
static int wtf(int logId, String tag, String msg, Throwable tr, boolean localStack,
boolean system) {
return printlns(LOG_ID_MAIN, WTF, tag, msg, tr);
}
private static final int LOG_ID_MAIN = 0;
private static final String[] PRIORITY_ABBREV = { "0", "1", "V", "D", "I", "W", "E", "A", "WTF" };
private static int println_native(int bufID, int priority, String tag, String msg) {
String res = PRIORITY_ABBREV[priority] + "/" + tag + " " + msg + System.lineSeparator();
System.err.print(res);
return res.length();
}
private static int printlns(int bufID, int priority, String tag, String msg,
Throwable tr) {
StringWriter trSW = new StringWriter();
if (tr != null) {
trSW.append(" , Exception: ");
PrintWriter trPW = new PrintWriter(trSW);
tr.printStackTrace(trPW);
trPW.flush();
}
return println_native(bufID, priority, tag, msg + trSW.toString());
}
}

View File

@ -2,14 +2,14 @@ package de.danoeh.antennapod.core.feed;
import java.util.Date;
import static de.danoeh.antennapod.core.feed.FeedImageMother.anyFeedImage;
import static de.danoeh.antennapod.core.feed.FeedMother.anyFeed;
class FeedItemMother {
private static final String IMAGE_URL = "http://example.com/image";
static FeedItem anyFeedItemWithImage() {
FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), FeedItem.PLAYED, anyFeed());
item.setImage(anyFeedImage());
item.setImageUrl(IMAGE_URL);
return item;
}

View File

@ -1,65 +1,60 @@
package de.danoeh.antennapod.core.feed;
import android.test.AndroidTestCase;
import org.junit.Before;
import org.junit.Test;
import static de.danoeh.antennapod.core.feed.FeedItemMother.anyFeedItemWithImage;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
public class FeedItemTest extends AndroidTestCase {
public class FeedItemTest {
private FeedItem original;
private FeedImage originalImage;
private FeedItem changedFeedItem;
@Override
protected void setUp() {
@Before
public void setUp() {
original = anyFeedItemWithImage();
originalImage = original.getImage();
changedFeedItem = anyFeedItemWithImage();
}
@Test
public void testUpdateFromOther_feedItemImageDownloadUrlChanged() throws Exception {
setNewFeedItemImageDownloadUrl();
original.updateFromOther(changedFeedItem);
feedItemImageWasUpdated();
assertFeedItemImageWasUpdated();
}
@Test
public void testUpdateFromOther_feedItemImageRemoved() throws Exception {
feedItemImageRemoved();
original.updateFromOther(changedFeedItem);
feedItemImageWasNotUpdated();
assertFeedItemImageWasNotUpdated();
}
@Test
public void testUpdateFromOther_feedItemImageAdded() throws Exception {
feedItemHadNoImage();
original.setImageUrl(null);
setNewFeedItemImageDownloadUrl();
original.updateFromOther(changedFeedItem);
feedItemImageWasUpdated();
}
private void feedItemHadNoImage() {
original.setImage(null);
assertFeedItemImageWasUpdated();
}
private void setNewFeedItemImageDownloadUrl() {
changedFeedItem.getImage().setDownload_url("http://example.com/new_picture");
changedFeedItem.setImageUrl("http://example.com/new_picture");
}
private void feedItemImageRemoved() {
changedFeedItem.setImage(null);
changedFeedItem.setImageUrl(null);
}
private void feedItemImageWasUpdated() {
assertEquals(original.getImage().getDownload_url(), changedFeedItem.getImage().getDownload_url());
private void assertFeedItemImageWasUpdated() {
assertEquals(original.getImageUrl(), changedFeedItem.getImageUrl());
}
private void feedItemImageWasNotUpdated() {
assertTrue(originalImage == original.getImage());
private void assertFeedItemImageWasNotUpdated() {
assertEquals(anyFeedItemWithImage().getImageUrl(), original.getImageUrl());
}
}

View File

@ -1,13 +1,11 @@
package de.danoeh.antennapod.core.feed;
import static de.danoeh.antennapod.core.feed.FeedImageMother.anyFeedImage;
class FeedMother {
public static final String IMAGE_URL = "http://example.com/image";
public static Feed anyFeed() {
FeedImage image = anyFeedImage();
return new Feed(0, null, "title", "http://example.com", "This is the description",
"http://example.com/payment", "Daniel", "en", null, "http://example.com/feed", image,
"http://example.com/payment", "Daniel", "en", null, "http://example.com/feed", IMAGE_URL,
null, "http://example.com/feed", true);
}

View File

@ -1,63 +1,61 @@
package de.danoeh.antennapod.core.feed;
import android.test.AndroidTestCase;
import org.junit.Before;
import org.junit.Test;
import static de.danoeh.antennapod.core.feed.FeedImageMother.anyFeedImage;
import static de.danoeh.antennapod.core.feed.FeedMother.anyFeed;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class FeedTest extends AndroidTestCase {
public class FeedTest {
private Feed original;
private FeedImage originalImage;
private Feed changedFeed;
@Override
protected void setUp() {
@Before
public void setUp() {
original = anyFeed();
originalImage = original.getImage();
changedFeed = anyFeed();
}
@Test
public void testCompareWithOther_feedImageDownloadUrlChanged() throws Exception {
setNewFeedImageDownloadUrl();
feedHasChanged();
}
@Test
public void testCompareWithOther_sameFeedImage() throws Exception {
changedFeed.setImage(anyFeedImage());
changedFeed.setImageUrl(FeedMother.IMAGE_URL);
feedHasNotChanged();
}
@Test
public void testCompareWithOther_feedImageRemoved() throws Exception {
feedImageRemoved();
feedHasNotChanged();
}
@Test
public void testUpdateFromOther_feedImageDownloadUrlChanged() throws Exception {
setNewFeedImageDownloadUrl();
original.updateFromOther(changedFeed);
feedImageWasUpdated();
}
@Test
public void testUpdateFromOther_feedImageRemoved() throws Exception {
feedImageRemoved();
original.updateFromOther(changedFeed);
feedImageWasNotUpdated();
}
@Test
public void testUpdateFromOther_feedImageAdded() throws Exception {
feedHadNoImage();
setNewFeedImageDownloadUrl();
original.updateFromOther(changedFeed);
feedImageWasUpdated();
}
@ -66,11 +64,11 @@ public class FeedTest extends AndroidTestCase {
}
private void feedHadNoImage() {
original.setImage(null);
original.setImageUrl(null);
}
private void setNewFeedImageDownloadUrl() {
changedFeed.getImage().setDownload_url("http://example.com/new_picture");
changedFeed.setImageUrl("http://example.com/new_picture");
}
private void feedHasChanged() {
@ -78,15 +76,15 @@ public class FeedTest extends AndroidTestCase {
}
private void feedImageRemoved() {
changedFeed.setImage(null);
changedFeed.setImageUrl(null);
}
private void feedImageWasUpdated() {
assertEquals(original.getImage().getDownload_url(), changedFeed.getImage().getDownload_url());
assertEquals(original.getImageUrl(), changedFeed.getImageUrl());
}
private void feedImageWasNotUpdated() {
assertTrue(originalImage == original.getImage());
assertEquals(anyFeed().getImageUrl(), original.getImageUrl());
}
}

View File

@ -1,11 +1,12 @@
package de.danoeh.antennapod.core.tests.util;
package de.danoeh.antennapod.core.util;
import android.test.AndroidTestCase;
import org.junit.Test;
import de.danoeh.antennapod.core.util.LongIntMap;
import static org.junit.Assert.assertEquals;
public class LongLongMapTest extends AndroidTestCase {
public class LongLongMapTest {
@Test
public void testEmptyMap() {
LongIntMap map = new LongIntMap();
assertEquals(0, map.size());
@ -18,6 +19,7 @@ public class LongLongMapTest extends AndroidTestCase {
assertEquals(1, map.hashCode());
}
@Test
public void testSingleElement() {
LongIntMap map = new LongIntMap();
map.put(17, 42);
@ -30,6 +32,7 @@ public class LongLongMapTest extends AndroidTestCase {
assertEquals(true, map.delete(17));
}
@Test
public void testAddAndDelete() {
LongIntMap map = new LongIntMap();
for(int i=0; i < 100; i++) {
@ -46,6 +49,7 @@ public class LongLongMapTest extends AndroidTestCase {
}
}
@Test
public void testOverwrite() {
LongIntMap map = new LongIntMap();
map.put(17, 42);