diff options
author | daniel oeh <daniel.oeh@gmail.com> | 2014-12-08 19:18:34 +0100 |
---|---|---|
committer | daniel oeh <daniel.oeh@gmail.com> | 2014-12-08 19:18:34 +0100 |
commit | 9659c18d899349d9be1573fb9520defc7d3a19cd (patch) | |
tree | c3e873c60b2b9990cdf47c9b4e5fca9ba70a0557 | |
parent | 563ceaf39332943b1733036f5c3b9087c481d313 (diff) | |
parent | 43243c1b70b6cae7f7ce3105e171afa6f9982144 (diff) | |
download | AntennaPod-9659c18d899349d9be1573fb9520defc7d3a19cd.zip |
Merge branch 'develop'0.9.9.6
54 files changed, 577 insertions, 377 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 17f5729bf..b01ca4bd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ Change Log ========== +Version 0.9.9.6 +--------------- +* Fixed problems related to variable playback speed plugins +* Fixed automatic feed update problems +* Several other bugfixes and improvements + Version 0.9.9.5 --------------- * Added support for paged feeds diff --git a/app/build.gradle b/app/build.gradle index cf1af78fa..14897139b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,13 +7,12 @@ dependencies { compile 'com.android.support:support-v4:21.0.2' compile 'com.android.support:appcompat-v7:21.0.2' compile 'org.apache.commons:commons-lang3:3.3.2' - compile('org.shredzone.flattr4j:flattr4j-core:2.10') { + compile('org.shredzone.flattr4j:flattr4j-core:2.11') { exclude group: 'org.apache.httpcomponents', module: 'httpcore' exclude group: 'org.apache.httpcomponents', module: 'httpclient' exclude group: 'org.json', module: 'json' } compile 'commons-io:commons-io:2.4' - compile 'com.nineoldandroids:library:2.4.0' compile project('dslv:library') compile 'com.jayway.android.robotium:robotium-solo:5.2.1' compile 'org.jsoup:jsoup:1.7.3' diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java index a96c9a6d3..1f6a907d4 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java @@ -2,6 +2,12 @@ package de.test.antennapod.storage; import android.content.Context; import android.test.InstrumentationTestCase; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Random; + import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; @@ -10,11 +16,6 @@ import de.danoeh.antennapod.core.storage.FeedItemStatistics; import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.core.util.flattr.FlattrStatus; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Random; - import static de.test.antennapod.storage.DBTestUtils.saveFeedlist; /** @@ -325,7 +326,7 @@ public class DBReaderTest extends InstrumentationTestCase { public void testGetPlaybackHistory() { final Context context = getInstrumentation().getTargetContext(); - final int numItems = (DBReader.PLAYBACK_HISTORY_SIZE+1) * 2; + final int numItems = (DBReader.PLAYBACK_HISTORY_SIZE + 1) * 2; final int playedItems = DBReader.PLAYBACK_HISTORY_SIZE + 1; final int numReturnedItems = Math.min(playedItems, DBReader.PLAYBACK_HISTORY_SIZE); final int numFeeds = 1; @@ -405,4 +406,64 @@ public class DBReaderTest extends InstrumentationTestCase { assertEquals(NUM_UNREAD, navDrawerData.numUnreadItems); assertEquals(NUM_QUEUE, navDrawerData.queueSize); } + + public void testGetFeedItemlistCheckChaptersFalse() throws Exception { + Context context = getInstrumentation().getTargetContext(); + List<Feed> feeds = DBTestUtils.saveFeedlist(context, 10, 10, false, false, 0); + for (Feed feed : feeds) { + for (FeedItem item : feed.getItems()) { + assertFalse(item.hasChapters()); + } + } + } + + public void testGetFeedItemlistCheckChaptersTrue() throws Exception { + Context context = getInstrumentation().getTargetContext(); + List<Feed> feeds = saveFeedlist(context, 10, 10, false, true, 10); + for (Feed feed : feeds) { + for (FeedItem item : feed.getItems()) { + assertTrue(item.hasChapters()); + } + } + } + + public void testLoadChaptersOfFeedItemNoChapters() throws Exception { + Context context = getInstrumentation().getTargetContext(); + List<Feed> feeds = saveFeedlist(context, 1, 3, false, false, 0); + saveFeedlist(context, 1, 3, false, true, 3); + for (Feed feed : feeds) { + for (FeedItem item : feed.getItems()) { + assertFalse(item.hasChapters()); + DBReader.loadChaptersOfFeedItem(context, item); + assertFalse(item.hasChapters()); + assertNull(item.getChapters()); + } + } + } + + public void testLoadChaptersOfFeedItemWithChapters() throws Exception { + Context context = getInstrumentation().getTargetContext(); + final int NUM_CHAPTERS = 3; + DBTestUtils.saveFeedlist(context, 1, 3, false, false, 0); + List<Feed> feeds = saveFeedlist(context, 1, 3, false, true, NUM_CHAPTERS); + for (Feed feed : feeds) { + for (FeedItem item : feed.getItems()) { + assertTrue(item.hasChapters()); + DBReader.loadChaptersOfFeedItem(context, item); + assertTrue(item.hasChapters()); + assertNotNull(item.getChapters()); + assertEquals(NUM_CHAPTERS, item.getChapters().size()); + } + } + } + + public void testGetItemWithChapters() throws Exception { + Context context = getInstrumentation().getTargetContext(); + final int NUM_CHAPTERS = 3; + List<Feed> feeds = saveFeedlist(context, 1, 1, false, true, NUM_CHAPTERS); + FeedItem item1 = feeds.get(0).getItems().get(0); + FeedItem item2 = DBReader.getFeedItem(context, item1.getId()); + assertTrue(item2.hasChapters()); + assertEquals(item1.getChapters(), item2.getChapters()); + } } diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java b/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java index 9e5f6546d..17c926cc2 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java @@ -1,12 +1,7 @@ package de.test.antennapod.storage; import android.content.Context; -import de.danoeh.antennapod.core.feed.Feed; -import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.feed.FeedMedia; -import de.danoeh.antennapod.core.storage.PodDBAdapter; -import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator; -import de.danoeh.antennapod.core.util.flattr.FlattrStatus; + import junit.framework.Assert; import java.util.ArrayList; @@ -14,12 +9,32 @@ import java.util.Collections; import java.util.Date; import java.util.List; +import de.danoeh.antennapod.core.feed.Chapter; +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.feed.SimpleChapter; +import de.danoeh.antennapod.core.storage.PodDBAdapter; +import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator; +import de.danoeh.antennapod.core.util.flattr.FlattrStatus; + /** * Utility methods for DB* tests. */ public class DBTestUtils { + /** + * Use this method when tests don't involve chapters. + */ public static List<Feed> saveFeedlist(Context context, int numFeeds, int numItems, boolean withMedia) { + return saveFeedlist(context, numFeeds, numItems, withMedia, false, 0); + } + + /** + * Use this method when tests involve chapters. + */ + public static List<Feed> saveFeedlist(Context context, int numFeeds, int numItems, boolean withMedia, + boolean withChapters, int numChapters) { if (numFeeds <= 0) { throw new IllegalArgumentException("numFeeds<=0"); } @@ -36,11 +51,18 @@ public class DBTestUtils { f.setItems(new ArrayList<FeedItem>()); for (int j = 0; j < numItems; j++) { FeedItem item = new FeedItem(0, "item " + j, "id" + j, "link" + j, new Date(), - true, f); + true, f, withChapters); if (withMedia) { FeedMedia media = new FeedMedia(item, "url" + j, 1, "audio/mp3"); item.setMedia(media); } + if (withChapters) { + List<Chapter> chapters = new ArrayList<>(); + item.setChapters(chapters); + for (int k = 0; k < numChapters; k++) { + chapters.add(new SimpleChapter(k, "item " + j + " chapter " + k, item, "http://example.com")); + } + } f.getItems().add(item); } Collections.sort(f.getItems(), new FeedItemPubdateComparator()); @@ -52,6 +74,7 @@ public class DBTestUtils { feeds.add(f); } adapter.close(); + return feeds; } } diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java index 4678a843b..ec8e19e22 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java @@ -4,10 +4,13 @@ import android.content.Context; import android.database.Cursor; import android.test.InstrumentationTestCase; import android.util.Log; + +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; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.PodDBAdapter; @@ -101,7 +104,7 @@ public class DBWriterTest extends InstrumentationTestCase { List<File> itemFiles = new ArrayList<File>(); // 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(), true, feed); + FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), true, feed, true); feed.getItems().add(item); File enc = new File(destFolder, "file " + i); @@ -110,6 +113,9 @@ public class DBWriterTest extends InstrumentationTestCase { FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null, 0); item.setMedia(media); + + item.setChapters(new ArrayList<Chapter>()); + item.getChapters().add(new SimpleChapter(0, "item " + i, item, "example.com")); } PodDBAdapter adapter = new PodDBAdapter(getInstrumentation().getContext()); @@ -122,6 +128,7 @@ public class DBWriterTest extends InstrumentationTestCase { 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); @@ -135,18 +142,20 @@ public class DBWriterTest extends InstrumentationTestCase { adapter = new PodDBAdapter(getInstrumentation().getContext()); adapter.open(); Cursor c = adapter.getFeedCursor(feed.getId()); - assertTrue(c.getCount() == 0); + assertEquals(0, c.getCount()); c.close(); c = adapter.getImageCursor(image.getId()); - assertTrue(c.getCount() == 0); + assertEquals(0, c.getCount()); c.close(); for (FeedItem item : feed.getItems()) { c = adapter.getFeedItemCursor(String.valueOf(item.getId())); - assertTrue(c.getCount() == 0); + assertEquals(0, c.getCount()); c.close(); c = adapter.getSingleFeedMediaCursor(item.getMedia().getId()); - assertTrue(c.getCount() == 0); + assertEquals(0, c.getCount()); c.close(); + c = adapter.getSimpleChaptersOfFeedItemCursor(item); + assertEquals(0, c.getCount()); } } diff --git a/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java b/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java index 47b58268b..aa197b6e1 100644 --- a/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java +++ b/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java @@ -73,4 +73,32 @@ public class URLCheckerTest extends AndroidTestCase { final String out = URLChecker.prepareURL(in); assertEquals("https://example.com", out); } + + public void testProtocolRelativeUrlIsAbsolute() throws Exception { + final String in = "https://example.com"; + final String inBase = "http://examplebase.com"; + final String out = URLChecker.prepareURL(in, inBase); + assertEquals(in, out); + } + + public void testProtocolRelativeUrlIsRelativeHttps() throws Exception { + final String in = "//example.com"; + final String inBase = "https://examplebase.com"; + final String out = URLChecker.prepareURL(in, inBase); + assertEquals("https://example.com", out); + + } + + public void testProtocolRelativeUrlIsHttpsWithAPSubscribeProtocol() throws Exception { + final String in = "//example.com"; + final String inBase = "antennapod-subscribe://https://examplebase.com"; + final String out = URLChecker.prepareURL(in, inBase); + assertEquals("https://example.com", out); + } + + public void testProtocolRelativeUrlBaseUrlNull() throws Exception { + final String in = "example.com"; + final String out = URLChecker.prepareURL(in, null); + assertEquals("http://example.com", out); + } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 44eee8539..50d1d2874 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.danoeh.antennapod" - android:versionCode="42" - android:versionName="0.9.9.5"> + android:versionCode="43" + android:versionName="0.9.9.6"> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> diff --git a/app/src/main/assets/about.html b/app/src/main/assets/about.html index e0f36ba79..172b49aab 100644 --- a/app/src/main/assets/about.html +++ b/app/src/main/assets/about.html @@ -41,7 +41,7 @@ <div id="header" align="center"> <img src="logo.png" alt="Logo" width="100px" height="100px"/> - <p>AntennaPod, Version 0.9.9.5</p> + <p>AntennaPod, Version 0.9.9.6</p> <p>Copyright © 2014 Daniel Oeh</p> @@ -49,9 +49,6 @@ </div> <h1>Used libraries</h1> -<h2>NineOldAndroids <a href="http://nineoldandroids.com">(Link)</a></h2> -by Jake Wharton, licensed under the Apache 2.0 license <a href="LICENSE_NINE_OLD_ANDROIDS.txt">(View)</a> - <h2>Apache Commons <a href="http://commons.apache.org/">(Link)</a></h2> by The Apache Software Foundation, licensed under the Apache 2.0 license <a href="LICENSE_APACHE_COMMONS.txt">(View)</a> @@ -65,12 +62,9 @@ licensed under the Apache 2.0 license <a href="LICENSE_DSLV.txt">(View)</a> <h2>Presto Client <a href="http://www.aocate.com/presto/">(Link)</a></h2> licensed under the Apache 2.0 license <a href="LICENSE_PRESTO.txt">(View)</a> -<h2>Better Pickers <a href="https://github.com/derekbrameyer/android-betterpickers">(Link)</a></h2> -licensed under the Apache 2.0 license <a href="LICENSE_BETTERPICKERS.txt">(View)</a> - <h2>jsoup <a href="http://jsoup.org/">(Link)</a></h2> licensed under the MIT license <a href="LICENSE_JSOUP.txt">(View)</a> -</body> + <h2>Picasso <a href="https://github.com/square/picasso">(Link)</a></h2> licensed under the Apache 2.0 license <a href="LICENSE_PICASSO.txt">(View)</a> @@ -83,4 +77,5 @@ licensed under the Apache 2.0 license <a href="LICENSE_OKIO.txt">(View)</a> <h2>Material Design Icons <a href="https://github.com/google/material-design-icons">(Link)</a></h2> by Google, licensed under an Attribution-ShareAlike 4.0 International license <a href="LICENSE_MATERIAL_DESIGN_ICONS.txt">(View)</a> +</body> </html> diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java index cf7de1709..811628ebf 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java @@ -4,29 +4,43 @@ import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.webkit.WebView; import android.webkit.WebViewClient; +import android.widget.LinearLayout; + import de.danoeh.antennapod.R; -/** Displays the 'about' screen */ +/** + * Displays the 'about' screen + */ public class AboutActivity extends ActionBarActivity { - private WebView webview; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getSupportActionBar().hide(); - setContentView(R.layout.about); - webview = (WebView) findViewById(R.id.webvAbout); - webview.setWebViewClient(new WebViewClient() { - - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - view.loadUrl(url); - return false; - } - - }); - webview.loadUrl("file:///android_asset/about.html"); - } + private WebView webview; + private LinearLayout webviewContainer; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getSupportActionBar().hide(); + setContentView(R.layout.about); + webviewContainer = (LinearLayout) findViewById(R.id.webvContainer); + webview = (WebView) findViewById(R.id.webvAbout); + webview.setWebViewClient(new WebViewClient() { + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + view.loadUrl(url); + return false; + } + + }); + webview.loadUrl("file:///android_asset/about.html"); + } + @Override + protected void onDestroy() { + super.onDestroy(); + if (webviewContainer != null && webview != null) { + webviewContainer.removeAllViews(); + webview.destroy(); + } + } } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java index d265c05b1..8401b41a7 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java @@ -123,7 +123,7 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity { subscribeButton = (Button) header.findViewById(R.id.butSubscribe); - if (feed.getImage() != null && StringUtils.isNoneBlank(feed.getImage().getDownload_url())) { + if (feed.getImage() != null && StringUtils.isNotBlank(feed.getImage().getDownload_url())) { Picasso.with(this) .load(feed.getImage().getDownload_url()) .fit() diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java index d625f21da..727b25296 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java @@ -54,6 +54,7 @@ public class VideoplayerActivity extends MediaplayerActivity { @Override protected void onCreate(Bundle savedInstanceState) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN); supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR_OVERLAY); // has to be called before setting layout content super.onCreate(savedInstanceState); getSupportActionBar().setBackgroundDrawable(new ColorDrawable(0x80000000)); @@ -116,6 +117,13 @@ public class VideoplayerActivity extends MediaplayerActivity { videoview.getHolder().addCallback(surfaceHolderCallback); videoview.setOnTouchListener(onVideoviewTouched); + if (Build.VERSION.SDK_INT >= 16) { + videoview.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); + } + if (Build.VERSION.SDK_INT >= 14) { + videoOverlay.setFitsSystemWindows(true); + } + setupVideoControlsToggler(); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); @@ -333,10 +341,10 @@ public class VideoplayerActivity extends MediaplayerActivity { butPlay.startAnimation(animation); } if (Build.VERSION.SDK_INT >= 14) { - videoview.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE); - getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); - + int videoviewFlag = (Build.VERSION.SDK_INT >= 16) ? View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION : 0; + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | videoviewFlag); + videoOverlay.setFitsSystemWindows(true); } videoOverlay.setVisibility(View.GONE); butPlay.setVisibility(View.GONE); diff --git a/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java index de2cb5ffb..8941a5d71 100644 --- a/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java +++ b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java @@ -8,7 +8,7 @@ import de.danoeh.antennapod.core.ClientConfig; public class ClientConfigurator { static { - ClientConfig.USER_AGENT = "AntennaPod/0.9.9.5"; + ClientConfig.USER_AGENT = "AntennaPod/0.9.9.6"; ClientConfig.applicationCallbacks = new ApplicationCallbacksImpl(); ClientConfig.downloadServiceCallbacks = new DownloadServiceCallbacksImpl(); ClientConfig.gpodnetCallbacks = new GpodnetCallbacksImpl(); diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/FeedItemDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/FeedItemDialog.java index 613cd1fec..eeed10b98 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/FeedItemDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/FeedItemDialog.java @@ -16,6 +16,7 @@ import android.util.Log; import android.util.TypedValue; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.view.Window; import android.webkit.WebSettings; import android.webkit.WebView; @@ -54,6 +55,7 @@ public class FeedItemDialog extends Dialog { private FeedItem item; private QueueAccess queue; + private ViewGroup contentContainer; private View header; private TextView txtvTitle; private WebView webvDescription; @@ -107,6 +109,7 @@ public class FeedItemDialog extends Dialog { requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.feeditem_dialog); + contentContainer = (ViewGroup) findViewById(R.id.contentContainer); txtvTitle = (TextView) findViewById(R.id.txtvTitle); header = findViewById(R.id.header); webvDescription = (WebView) findViewById(R.id.webview); @@ -225,6 +228,14 @@ public class FeedItemDialog extends Dialog { updateMenuAppearance(); } + @Override + public void dismiss() { + super.dismiss(); + if (contentContainer != null && webvDescription != null) { + contentContainer.removeAllViews(); + webvDescription.destroy(); + } + } private final FeedItemMenuHandler.MenuInterface popupMenuInterface = new FeedItemMenuHandler.MenuInterface() { @Override diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java index 4a5c3f718..c0222de8e 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java @@ -162,11 +162,6 @@ public class ItemDescriptionFragment extends Fragment { } @Override - public void onDestroyView() { - super.onDestroyView(); - } - - @Override public void onAttach(Activity activity) { super.onAttach(activity); if (BuildConfig.DEBUG) @@ -191,6 +186,10 @@ public class ItemDescriptionFragment extends Fragment { if (webViewLoader != null) { webViewLoader.cancel(true); } + if (webvDescription != null) { + webvDescription.removeAllViews(); + webvDescription.destroy(); + } } @SuppressLint("NewApi") diff --git a/app/src/main/res/layout/about.xml b/app/src/main/res/layout/about.xml index acde9d786..02e232d9a 100644 --- a/app/src/main/res/layout/about.xml +++ b/app/src/main/res/layout/about.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/webvContainer" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > diff --git a/app/src/main/res/layout/feeditem_dialog.xml b/app/src/main/res/layout/feeditem_dialog.xml index 24abae762..5937480df 100644 --- a/app/src/main/res/layout/feeditem_dialog.xml +++ b/app/src/main/res/layout/feeditem_dialog.xml @@ -1,58 +1,59 @@ <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - android:layout_width="match_parent" - android:layout_height="match_parent"> + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/contentContainer" + android:layout_width="match_parent" + android:layout_height="match_parent"> <TextView + android:id="@+id/txtvTitle" + style="@style/AntennaPod.Dialog.Title" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_margin="16dp" - android:id="@+id/txtvTitle" android:layout_alignParentTop="true" - style="@style/AntennaPod.Dialog.Title" - android:maxLines="5" - android:ellipsize="none"/> + android:layout_margin="16dp" + android:ellipsize="none" + android:maxLines="5" /> <View android:id="@+id/title_divider" android:layout_width="match_parent" android:layout_height="2dp" android:layout_below="@id/txtvTitle" - android:background="@color/bright_blue"/> + android:background="@color/bright_blue" /> <LinearLayout android:id="@+id/header" - android:orientation="horizontal" - android:layout_below="@id/title_divider" android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:layout_below="@id/title_divider" + android:orientation="horizontal"> <ImageButton + android:id="@+id/butAction1" android:layout_width="0dp" android:layout_height="48dp" android:layout_weight="1" - android:id="@+id/butAction1" android:background="?attr/selectableItemBackground" - tools:ignore="ContentDescription"/> + tools:ignore="ContentDescription" /> <ImageButton + android:id="@+id/butAction2" android:layout_width="0dp" android:layout_height="48dp" android:layout_weight="1" - android:id="@+id/butAction2" android:background="?attr/selectableItemBackground" - tools:ignore="ContentDescription"/> + tools:ignore="ContentDescription" /> <ImageButton + android:id="@+id/butMoreActions" android:layout_width="0dp" android:layout_height="48dp" android:layout_weight="1" - android:id="@+id/butMoreActions" android:background="?attr/selectableItemBackground" - android:src="?attr/ic_action_overflow" - android:contentDescription="@string/butAction_label"/> + android:contentDescription="@string/butAction_label" + android:src="?attr/ic_action_overflow" /> </LinearLayout> <View @@ -60,13 +61,13 @@ android:layout_width="match_parent" android:layout_height="2dp" android:layout_below="@id/header" - android:background="@color/bright_blue"/> + android:background="@color/bright_blue" /> <WebView + android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="0dp" - android:layout_below="@id/divider" android:layout_alignParentBottom="true" - android:id="@+id/webview"/> + android:layout_below="@id/divider" /> </RelativeLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/videoplayer_activity.xml b/app/src/main/res/layout/videoplayer_activity.xml index f1e54f7c3..766cd6e04 100644 --- a/app/src/main/res/layout/videoplayer_activity.xml +++ b/app/src/main/res/layout/videoplayer_activity.xml @@ -1,47 +1,46 @@ <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical"> + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/black" + android:orientation="vertical"> <de.danoeh.antennapod.view.AspectRatioVideoView android:id="@+id/videoview" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center"/> + android:layout_gravity="center" /> <ProgressBar android:id="@+id/progressIndicator" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:visibility="invisible" - android:indeterminateOnly="true"/> + android:indeterminateOnly="true" + android:visibility="invisible" /> <ImageButton android:id="@+id/butPlay" - android:contentDescription="@string/pause_label" - android:layout_width="80dp" - android:layout_height="80dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_gravity="center" - android:scaleType="fitXY" android:background="@drawable/overlay_button_circle_background" - android:src="@drawable/ic_action_pause_over_video"/> + android:contentDescription="@string/pause_label" + android:src="@drawable/ic_av_pause_circle_outline_80dp" /> <LinearLayout android:id="@+id/overlay" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom|center" - android:background="#80000000" android:orientation="vertical"> <RelativeLayout android:id="@+id/timecontrol" android:layout_width="match_parent" android:layout_height="50dp" - android:paddingTop="8dp" - android:layout_marginBottom="4dp"> + android:background="#80000000" + android:paddingTop="8dp"> <TextView android:id="@+id/txtvPosition" @@ -53,9 +52,9 @@ android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginTop="4dp" + android:text="@string/position_default_label" android:textColor="@color/white" - android:textStyle="bold" - android:text="@string/position_default_label"/> + android:textStyle="bold" /> <TextView android:id="@+id/txtvLength" @@ -67,9 +66,9 @@ android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginTop="4dp" + android:text="@string/position_default_label" android:textColor="@color/white" - android:textStyle="bold" - android:text="@string/position_default_label"/> + android:textStyle="bold" /> <SeekBar android:id="@+id/sbPosition" @@ -77,7 +76,7 @@ android:layout_height="wrap_content" android:layout_toLeftOf="@+id/txtvLength" android:layout_toRightOf="@+id/txtvPosition" - android:max="500"/> + android:max="500" /> </RelativeLayout> </LinearLayout> diff --git a/build.gradle b/build.gradle index 9c6a1f9d8..efa6e1773 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:0.14.2' + classpath 'com.android.tools.build:gradle:1.0.0-rc4' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -19,5 +19,5 @@ allprojects { } task wrapper(type: Wrapper) { - gradleVersion = '2.1' + gradleVersion = '2.2.1' }
\ No newline at end of file diff --git a/core/build.gradle b/core/build.gradle index 3c5c07313..cfe33c98c 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -5,7 +5,6 @@ android { buildToolsVersion "21.1.1" defaultConfig { - applicationId "de.danoeh.antennapod.core" minSdkVersion 10 targetSdkVersion 21 versionCode 1 @@ -35,13 +34,12 @@ dependencies { compile 'com.android.support:appcompat-v7:21.0.2' compile 'com.android.support:support-v4:21.0.2' compile 'org.apache.commons:commons-lang3:3.3.2' - compile ('org.shredzone.flattr4j:flattr4j-core:2.10') { + compile ('org.shredzone.flattr4j:flattr4j-core:2.11') { exclude group: 'org.apache.httpcomponents', module: 'httpcore' exclude group: 'org.apache.httpcomponents', module: 'httpclient' exclude group: 'org.json', module: 'json' } compile 'commons-io:commons-io:2.4' - compile 'com.nineoldandroids:library:2.4.0' compile 'com.jayway.android.robotium:robotium-solo:5.2.1' compile 'org.jsoup:jsoup:1.7.3' compile 'com.squareup.picasso:picasso:2.4.0' diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml index c660cd805..3ec519844 100644 --- a/core/src/main/AndroidManifest.xml +++ b/core/src/main/AndroidManifest.xml @@ -19,10 +19,10 @@ <service android:name=".service.playback.PlaybackService" android:enabled="true" - android:exported="true"/> + android:exported="true" /> <service android:name=".service.GpodnetSyncService" - android:enabled="true"/> + android:enabled="true" /> <receiver android:name=".receiver.MediaButtonReceiver" @@ -47,6 +47,9 @@ </intent-filter> </receiver> + <receiver android:name=".receiver.FeedUpdateReceiver"> + </receiver> + </application> </manifest> diff --git a/core/src/main/java/com/aocate/media/MediaPlayer.java b/core/src/main/java/com/aocate/media/MediaPlayer.java index c73c5219e..79e63d03d 100644 --- a/core/src/main/java/com/aocate/media/MediaPlayer.java +++ b/core/src/main/java/com/aocate/media/MediaPlayer.java @@ -35,6 +35,8 @@ import java.util.concurrent.locks.ReentrantLock; import de.danoeh.antennapod.core.BuildConfig; public class MediaPlayer { + public static final String TAG = "com.aocate.media.MediaPlayer"; + public interface OnBufferingUpdateListener { public abstract void onBufferingUpdate(MediaPlayer arg0, int percent); } @@ -110,6 +112,36 @@ public class MediaPlayer { } /** + * Returns an explicit Intent for a service that accepts the given Intent + * or null if no such service was found. + * + * @param context The application's environment. + * @param action The Intent action to check for availability. + * @return The explicit service Intent or null if no service was found. + */ + public static Intent getPrestoServiceIntent(Context context, String action) { + final PackageManager packageManager = context.getPackageManager(); + final Intent actionIntent = new Intent(action); + List<ResolveInfo> list = packageManager.queryIntentServices(actionIntent, + PackageManager.MATCH_DEFAULT_ONLY); + if (list.size() > 0) { + ResolveInfo first = list.get(0); + if (first.serviceInfo != null) { + Intent intent = new Intent(); + intent.setComponent(new ComponentName(first.serviceInfo.packageName, + first.serviceInfo.name)); + Log.i(TAG, "Returning intent:" + intent.toString()); + return intent; + } else { + Log.e(TAG, "Found service that accepts " + action + ", but serviceInfo was null"); + return null; + } + } else { + return null; + } + } + + /** * Indicates whether the Presto library is installed * * @param context The context to use to query the package manager. diff --git a/core/src/main/java/com/aocate/media/ServiceBackedMediaPlayer.java b/core/src/main/java/com/aocate/media/ServiceBackedMediaPlayer.java index 702a23b0f..0e27a8014 100644 --- a/core/src/main/java/com/aocate/media/ServiceBackedMediaPlayer.java +++ b/core/src/main/java/com/aocate/media/ServiceBackedMediaPlayer.java @@ -83,7 +83,7 @@ public class ServiceBackedMediaPlayer extends MediaPlayerImpl { super(owningMediaPlayer, context); Log.d(SBMP_TAG, "Instantiating ServiceBackedMediaPlayer 87"); this.playMediaServiceIntent = - new Intent(INTENT_NAME); + MediaPlayer.getPrestoServiceIntent(context, INTENT_NAME); this.mPlayMediaServiceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { IPlayMedia_0_8 tmpPlayMediaInterface = IPlayMedia_0_8.Stub.asInterface((IBinder) service); @@ -135,6 +135,7 @@ public class ServiceBackedMediaPlayer extends MediaPlayerImpl { Log.d(SBMP_TAG, "Connecting PlayMediaService 124"); if (!ConnectPlayMediaService()) { + Log.e(SBMP_TAG, "bindService failed"); ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); } } @@ -149,6 +150,7 @@ public class ServiceBackedMediaPlayer extends MediaPlayerImpl { Log.d(SBMP_TAG, "Binding service"); return mContext.bindService(playMediaServiceIntent, mPlayMediaServiceConnection, Context.BIND_AUTO_CREATE); } catch (Exception e) { + Log.e(SBMP_TAG, "Could not bind with service", e); return false; } } else { diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java index d056917e1..42e4191f6 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java @@ -44,12 +44,45 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr private boolean read; private String paymentLink; private FlattrStatus flattrStatus; + + /** + * Is true if the database contains any chapters that belong to this item. This attribute is only + * written once by DBReader on initialization. + * The FeedItem might still have a non-null chapters value. In this case, the list of chapters + * has not been saved in the database yet. + * */ + private final boolean hasChapters; + + /** + * The list of chapters of this item. This might be null even if there are chapters of this item + * in the database. The 'hasChapters' attribute should be used to check if this item has any chapters. + * */ private List<Chapter> chapters; private FeedImage image; public FeedItem() { this.read = true; this.flattrStatus = new FlattrStatus(); + this.hasChapters = false; + } + + /** + * 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, boolean read, + String itemIdentifier) { + this.id = id; + this.title = title; + this.link = link; + this.pubDate = pubDate; + this.paymentLink = paymentLink; + this.feedId = feedId; + this.flattrStatus = flattrStatus; + this.hasChapters = hasChapters; + this.image = image; + this.read = read; + this.itemIdentifier = itemIdentifier; } /** @@ -64,6 +97,22 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr this.read = read; this.feed = feed; this.flattrStatus = new FlattrStatus(); + this.hasChapters = false; + } + + /** + * This constructor should be used for creating test objects involving chapter marks. + */ + public FeedItem(long id, String title, String itemIdentifier, String link, Date pubDate, boolean read, Feed feed, boolean hasChapters) { + this.id = id; + this.title = title; + this.itemIdentifier = itemIdentifier; + this.link = link; + this.pubDate = (pubDate != null) ? (Date) pubDate.clone() : null; + this.read = read; + this.feed = feed; + this.flattrStatus = new FlattrStatus(); + this.hasChapters = hasChapters; } public void updateFromOther(FeedItem other) { @@ -331,4 +380,8 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr public String getHumanReadableIdentifier() { return title; } + + public boolean hasChapters() { + return hasChapters; + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java index defcfd598..2434ee0cf 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java @@ -245,14 +245,19 @@ public class FeedMedia extends FeedFile implements Playable { @Override public void loadChapterMarks() { - if (getChapters() == null && !localFileAvailable()) { + if (item == null && itemID != 0) { + item = DBReader.getFeedItem(ClientConfig.applicationCallbacks.getApplicationInstance(), itemID); + } + // check if chapters are stored in db and not loaded yet. + if (item != null && item.hasChapters() && item.getChapters() == null) { + DBReader.loadChaptersOfFeedItem(ClientConfig.applicationCallbacks.getApplicationInstance(), item); + } else if (item != null && item.getChapters() == null && !localFileAvailable()) { ChapterUtils.loadChaptersFromStreamUrl(this); if (getChapters() != null && item != null) { DBWriter.setFeedItem(ClientConfig.applicationCallbacks.getApplicationInstance(), item); } } - } @Override diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java index f4d44c4da..f18028e8f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java +++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java @@ -20,6 +20,7 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; +import de.danoeh.antennapod.core.ApplicationCallbacks; import de.danoeh.antennapod.core.BuildConfig; import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.R; @@ -582,8 +583,7 @@ public class UserPreferences implements AlarmManager alarmManager = (AlarmManager) instance.context .getSystemService(Context.ALARM_SERVICE); PendingIntent updateIntent = PendingIntent.getBroadcast( - instance.context, 0, new Intent( - FeedUpdateReceiver.ACTION_REFRESH_FEEDS), 0); + instance.context, 0, new Intent(ClientConfig.applicationCallbacks.getApplicationInstance(), FeedUpdateReceiver.class), 0); alarmManager.cancel(updateIntent); if (intervalMillis != 0) { alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtMillis, intervalMillis, diff --git a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java index 6ce30763d..95dc4fb07 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java +++ b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java @@ -7,40 +7,37 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.util.Log; -import org.apache.commons.lang3.StringUtils; - import de.danoeh.antennapod.core.BuildConfig; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.DBTasks; -/** Refreshes all feeds when it receives an intent */ +/** + * Refreshes all feeds when it receives an intent + */ public class FeedUpdateReceiver extends BroadcastReceiver { - private static final String TAG = "FeedUpdateReceiver"; - public static final String ACTION_REFRESH_FEEDS = "de.danoeh.antennapod.feedupdatereceiver.refreshFeeds"; - - @Override - public void onReceive(Context context, Intent intent) { - if (StringUtils.equals(intent.getAction(), ACTION_REFRESH_FEEDS)) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Received intent"); - boolean mobileUpdate = UserPreferences.isAllowMobileUpdate(); - if (mobileUpdate || connectedToWifi(context)) { - DBTasks.refreshExpiredFeeds(context); - } else { - if (BuildConfig.DEBUG) - Log.d(TAG, - "Blocking automatic update: no wifi available / no mobile updates allowed"); - } - } - } - - private boolean connectedToWifi(Context context) { - ConnectivityManager connManager = (ConnectivityManager) context - .getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo mWifi = connManager - .getNetworkInfo(ConnectivityManager.TYPE_WIFI); - - return mWifi.isConnected(); - } + private static final String TAG = "FeedUpdateReceiver"; + + @Override + public void onReceive(Context context, Intent intent) { + if (BuildConfig.DEBUG) + Log.d(TAG, "Received intent"); + boolean mobileUpdate = UserPreferences.isAllowMobileUpdate(); + if (mobileUpdate || connectedToWifi(context)) { + DBTasks.refreshExpiredFeeds(context); + } else { + if (BuildConfig.DEBUG) + Log.d(TAG, + "Blocking automatic update: no wifi available / no mobile updates allowed"); + } + } + + private boolean connectedToWifi(Context context) { + ConnectivityManager connManager = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo mWifi = connManager + .getNetworkInfo(ConnectivityManager.TYPE_WIFI); + + return mWifi.isConnected(); + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java index 6c0b6df74..217e6fba5 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java @@ -4,8 +4,22 @@ import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.util.Log; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + import de.danoeh.antennapod.core.BuildConfig; -import de.danoeh.antennapod.core.feed.*; +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; +import de.danoeh.antennapod.core.feed.ID3Chapter; +import de.danoeh.antennapod.core.feed.SimpleChapter; +import de.danoeh.antennapod.core.feed.VorbisCommentChapter; import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.util.DownloadError; import de.danoeh.antennapod.core.util.comparator.DownloadStatusComparator; @@ -14,11 +28,6 @@ import de.danoeh.antennapod.core.util.comparator.PlaybackCompletionDateComparato import de.danoeh.antennapod.core.util.flattr.FlattrStatus; import de.danoeh.antennapod.core.util.flattr.FlattrThing; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.List; - /** * Provides methods for reading data from the AntennaPod database. * In general, all database calls in DBReader-methods are executed on the caller's thread. @@ -203,75 +212,26 @@ public final class DBReader { if (itemlistCursor.moveToFirst()) { do { - FeedItem item = new FeedItem(); - - item.setId(itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_ID)); - item.setTitle(itemlistCursor - .getString(PodDBAdapter.IDX_FI_SMALL_TITLE)); - item.setLink(itemlistCursor - .getString(PodDBAdapter.IDX_FI_SMALL_LINK)); - item.setPubDate(new Date(itemlistCursor - .getLong(PodDBAdapter.IDX_FI_SMALL_PUBDATE))); - item.setPaymentLink(itemlistCursor - .getString(PodDBAdapter.IDX_FI_SMALL_PAYMENT_LINK)); - item.setFeedId(itemlistCursor - .getLong(PodDBAdapter.IDX_FI_SMALL_FEED)); - itemIds.add(String.valueOf(item.getId())); - - item.setRead((itemlistCursor - .getInt(PodDBAdapter.IDX_FI_SMALL_READ) > 0)); - item.setItemIdentifier(itemlistCursor - .getString(PodDBAdapter.IDX_FI_SMALL_ITEM_IDENTIFIER)); - item.setFlattrStatus(new FlattrStatus(itemlistCursor - .getLong(PodDBAdapter.IDX_FI_SMALL_FLATTR_STATUS))); - long imageIndex = itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_IMAGE); + FeedImage image = null; if (imageIndex != 0) { - item.setImage(getFeedImage(adapter, imageIndex)); + image = getFeedImage(adapter, imageIndex); } - // extract chapters - boolean hasSimpleChapters = itemlistCursor - .getInt(PodDBAdapter.IDX_FI_SMALL_HAS_CHAPTERS) > 0; - if (hasSimpleChapters) { - Cursor chapterCursor = adapter - .getSimpleChaptersOfFeedItemCursor(item); - if (chapterCursor.moveToFirst()) { - item.setChapters(new ArrayList<Chapter>()); - do { - int chapterType = chapterCursor - .getInt(PodDBAdapter.KEY_CHAPTER_TYPE_INDEX); - Chapter chapter = null; - long start = chapterCursor - .getLong(PodDBAdapter.KEY_CHAPTER_START_INDEX); - String title = chapterCursor - .getString(PodDBAdapter.KEY_TITLE_INDEX); - String link = chapterCursor - .getString(PodDBAdapter.KEY_CHAPTER_LINK_INDEX); - - switch (chapterType) { - case SimpleChapter.CHAPTERTYPE_SIMPLECHAPTER: - chapter = new SimpleChapter(start, title, item, - link); - break; - case ID3Chapter.CHAPTERTYPE_ID3CHAPTER: - chapter = new ID3Chapter(start, title, item, - link); - break; - case VorbisCommentChapter.CHAPTERTYPE_VORBISCOMMENT_CHAPTER: - chapter = new VorbisCommentChapter(start, - title, item, link); - break; - } - if (chapter != null) { - chapter.setId(chapterCursor - .getLong(PodDBAdapter.KEY_ID_INDEX)); - item.getChapters().add(chapter); - } - } while (chapterCursor.moveToNext()); - } - chapterCursor.close(); - } + FeedItem item = new FeedItem(itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_ID), + itemlistCursor.getString(PodDBAdapter.IDX_FI_SMALL_TITLE), + itemlistCursor.getString(PodDBAdapter.IDX_FI_SMALL_LINK), + new Date(itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_PUBDATE)), + itemlistCursor.getString(PodDBAdapter.IDX_FI_SMALL_PAYMENT_LINK), + itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_FEED), + new FlattrStatus(itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_FLATTR_STATUS)), + itemlistCursor.getInt(PodDBAdapter.IDX_FI_SMALL_HAS_CHAPTERS) > 0, + image, + (itemlistCursor.getInt(PodDBAdapter.IDX_FI_SMALL_READ) > 0), + itemlistCursor.getString(PodDBAdapter.IDX_FI_SMALL_ITEM_IDENTIFIER)); + + itemIds.add(String.valueOf(item.getId())); + items.add(item); } while (itemlistCursor.moveToNext()); } @@ -367,6 +327,7 @@ public final class DBReader { return feed; } + private static FeedItem getMatchingItemForMedia(long itemId, List<FeedItem> items) { for (FeedItem item : items) { @@ -689,6 +650,9 @@ public final class DBReader { if (list.size() > 0) { item = list.get(0); loadFeedDataOfFeedItemlist(context, list); + if (item.hasChapters()) { + loadChaptersOfFeedItem(adapter, item); + } } } return item; @@ -696,12 +660,13 @@ public final class DBReader { } /** - * Loads a specific FeedItem from the database. + * Loads a specific FeedItem from the database. This method should not be used for loading more + * than one FeedItem because this method might query the database several times for each item. * * @param context A context that is used for opening a database connection. * @param itemId The ID of the FeedItem - * @return The FeedItem or null if the FeedItem could not be found. All FeedComponent-attributes of the FeedItem will - * also be loaded from the database. + * @return The FeedItem or null if the FeedItem could not be found. All FeedComponent-attributes + * as well as chapter marks of the FeedItem will also be loaded from the database. */ public static FeedItem getFeedItem(final Context context, final long itemId) { if (BuildConfig.DEBUG) @@ -737,6 +702,63 @@ public final class DBReader { } /** + * Loads the list of chapters that belongs to this FeedItem if available. This method overwrites + * any chapters that this FeedItem has. If no chapters were found in the database, the chapters + * reference of the FeedItem will be set to null. + * + * @param context A context that is used for opening a database connection. + * @param item The FeedItem + */ + public static void loadChaptersOfFeedItem(final Context context, final FeedItem item) { + PodDBAdapter adapter = new PodDBAdapter(context); + adapter.open(); + loadChaptersOfFeedItem(adapter, item); + adapter.close(); + } + + static void loadChaptersOfFeedItem(PodDBAdapter adapter, FeedItem item) { + Cursor chapterCursor = adapter + .getSimpleChaptersOfFeedItemCursor(item); + if (chapterCursor.moveToFirst()) { + item.setChapters(new ArrayList<Chapter>()); + do { + int chapterType = chapterCursor + .getInt(PodDBAdapter.KEY_CHAPTER_TYPE_INDEX); + Chapter chapter = null; + long start = chapterCursor + .getLong(PodDBAdapter.KEY_CHAPTER_START_INDEX); + String title = chapterCursor + .getString(PodDBAdapter.KEY_TITLE_INDEX); + String link = chapterCursor + .getString(PodDBAdapter.KEY_CHAPTER_LINK_INDEX); + + switch (chapterType) { + case SimpleChapter.CHAPTERTYPE_SIMPLECHAPTER: + chapter = new SimpleChapter(start, title, item, + link); + break; + case ID3Chapter.CHAPTERTYPE_ID3CHAPTER: + chapter = new ID3Chapter(start, title, item, + link); + break; + case VorbisCommentChapter.CHAPTERTYPE_VORBISCOMMENT_CHAPTER: + chapter = new VorbisCommentChapter(start, + title, item, link); + break; + } + if (chapter != null) { + chapter.setId(chapterCursor + .getLong(PodDBAdapter.KEY_ID_INDEX)); + item.getChapters().add(chapter); + } + } while (chapterCursor.moveToNext()); + } else { + item.setChapters(null); + } + chapterCursor.close(); + } + + /** * Returns the number of downloaded episodes. * * @param context A context that is used for opening a database connection. @@ -788,7 +810,7 @@ public final class DBReader { static FeedImage getFeedImage(PodDBAdapter adapter, final long id) { Cursor cursor = adapter.getImageCursor(id); if ((cursor.getCount() == 0) || !cursor.moveToFirst()) { - throw new SQLException("No FeedImage found at index: " + id); + return null; } FeedImage image = new FeedImage(id, cursor.getString(cursor .getColumnIndex(PodDBAdapter.KEY_TITLE)), diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java index 148d886ae..f5ee9e28c 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java @@ -90,7 +90,7 @@ public class DownloadRequester { return true; } - private void download(Context context, FeedFile item, File dest, + private void download(Context context, FeedFile item, FeedFile container, File dest, boolean overwriteIfExists, String username, String password, boolean deleteOnFailure, Bundle arguments) { if (!isDownloadingFile(item)) { if (!isFilenameAvailable(dest.toString()) || (deleteOnFailure && dest.exists())) { @@ -129,7 +129,8 @@ public class DownloadRequester { if (BuildConfig.DEBUG) Log.d(TAG, "Requesting download of url " + item.getDownload_url()); - item.setDownload_url(URLChecker.prepareURL(item.getDownload_url())); + String baseUrl = (container != null) ? container.getDownload_url() : null; + item.setDownload_url(URLChecker.prepareURL(item.getDownload_url(), baseUrl)); DownloadRequest request = new DownloadRequest(dest.toString(), URLChecker.prepareURL(item.getDownload_url()), item.getHumanReadableIdentifier(), @@ -171,7 +172,7 @@ public class DownloadRequester { args.putInt(REQUEST_ARG_PAGE_NR, feed.getPageNr()); args.putBoolean(REQUEST_ARG_LOAD_ALL_PAGES, loadAllPages); - download(context, feed, new File(getFeedfilePath(context), + download(context, feed, null, new File(getFeedfilePath(context), getFeedfileName(feed)), true, username, password, true, args); } } @@ -183,7 +184,8 @@ public class DownloadRequester { public synchronized void downloadImage(Context context, FeedImage image) throws DownloadRequestException { if (feedFileValid(image)) { - download(context, image, new File(getImagefilePath(context), + FeedFile container = (image.getOwner() instanceof FeedFile) ? (FeedFile) image.getOwner() : null; + download(context, image, container, new File(getImagefilePath(context), getImagefileName(image)), false, null, null, false, null); } } @@ -209,7 +211,7 @@ public class DownloadRequester { dest = new File(getMediafilePath(context, feedmedia), getMediafilename(feedmedia)); } - download(context, feedmedia, + download(context, feedmedia, feed, dest, false, username, password, false, null); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java index 79124521f..ce41147e1 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java @@ -693,7 +693,7 @@ public class PodDBAdapter { } values.put(KEY_FEED, item.getFeed().getId()); values.put(KEY_READ, item.isRead()); - values.put(KEY_HAS_CHAPTERS, item.getChapters() != null); + values.put(KEY_HAS_CHAPTERS, item.getChapters() != null || item.hasChapters()); values.put(KEY_ITEM_IDENTIFIER, item.getItemIdentifier()); values.put(KEY_FLATTR_STATUS, item.getFlattrStatus().toLong()); if (item.hasItemImage()) { @@ -848,7 +848,7 @@ public class PodDBAdapter { if (item.getMedia() != null) { removeFeedMedia(item.getMedia()); } - if (item.getChapters() != null) { + if (item.hasChapters() || item.getChapters() != null) { removeChaptersOfItem(item); } if (item.hasItemImage()) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java index 70e1126b9..ff9828eba 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java @@ -50,7 +50,7 @@ public class NSITunes extends Namespace { if (localName.equals(AUTHOR)) { state.getFeed().setAuthor(state.getContentBuf().toString()); } else if (localName.equals(DURATION)) { - String[] parts = state.getContentBuf().toString().split(":"); + String[] parts = state.getContentBuf().toString().trim().split(":"); try { int duration = 0; if (parts.length == 2) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndDateUtils.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndDateUtils.java index d493286ac..1ac389f08 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndDateUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndDateUtils.java @@ -7,13 +7,16 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; +import de.danoeh.antennapod.core.BuildConfig; + /** * Parses several date formats. */ public class SyndDateUtils { private static final String TAG = "DateUtils"; - private static final String[] RFC822DATES = {"dd MMM yy HH:mm:ss Z",}; + private static final String[] RFC822DATES = {"dd MMM yy HH:mm:ss Z", + "dd MMM yy HH:mm Z"}; /** * RFC 3339 date format for UTC dates. @@ -51,17 +54,18 @@ public class SyndDateUtils { date = date.substring(date.indexOf(",") + 1).trim(); } SimpleDateFormat format = RFC822Formatter.get(); - for (int i = 0; i < RFC822DATES.length; i++) { + + for (String RFC822DATE : RFC822DATES) { try { - format.applyPattern(RFC822DATES[i]); + format.applyPattern(RFC822DATE); result = format.parse(date); break; } catch (ParseException e) { - e.printStackTrace(); + if (BuildConfig.DEBUG) Log.d(TAG, "ParserException", e); } } if (result == null) { - Log.e(TAG, "Unable to parse feed date correctly"); + Log.e(TAG, "Unable to parse feed date correctly:" + date); } return result; @@ -134,9 +138,11 @@ public class SyndDateUtils { result += Integer.valueOf(parts[idx]) * 3600000L; idx++; } - result += Integer.valueOf(parts[idx]) * 60000L; - idx++; - result += (Float.valueOf(parts[idx])) * 1000L; + if (parts.length >= 2) { + result += Integer.valueOf(parts[idx]) * 60000L; + idx++; + result += (Float.valueOf(parts[idx])) * 1000L; + } return result; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java b/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java index 4bd18c8bc..4300556d2 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java @@ -1,5 +1,6 @@ package de.danoeh.antennapod.core.util; +import android.net.Uri; import android.util.Log; import org.apache.commons.lang3.StringUtils; @@ -51,4 +52,28 @@ public final class URLChecker { return url; } } + + /** + * Checks if URL is valid and modifies it if necessary. + * This method also handles protocol relative URLs. + * + * @param url The url which is going to be prepared + * @param base The url against which the (possibly relative) url is applied. If this is null, + * the result of prepareURL(url) is returned instead. + * @return The prepared url + */ + public static String prepareURL(String url, String base) { + if (base == null) { + return prepareURL(url); + } + url = StringUtils.trim(url); + base = prepareURL(base); + Uri urlUri = Uri.parse(url); + Uri baseUri = Uri.parse(base); + if (urlUri.isRelative() && baseUri.isAbsolute()) { + return urlUri.buildUpon().scheme(baseUri.getScheme()).build().toString(); + } else { + return prepareURL(url); + } + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/UndoBarController.java b/core/src/main/java/de/danoeh/antennapod/core/util/UndoBarController.java deleted file mode 100644 index 5843c5f8f..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/UndoBarController.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2012 Roman Nurik - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.danoeh.antennapod.core.util; - -import android.os.Bundle; -import android.os.Handler; -import android.os.Parcelable; -import android.text.TextUtils; -import android.view.View; -import android.widget.TextView; -import com.nineoldandroids.animation.Animator; -import com.nineoldandroids.animation.AnimatorListenerAdapter; -import com.nineoldandroids.view.ViewHelper; -import com.nineoldandroids.view.ViewPropertyAnimator; -import de.danoeh.antennapod.core.R; - -import static com.nineoldandroids.view.ViewPropertyAnimator.animate; - -public class UndoBarController { - private View mBarView; - private TextView mMessageView; - private ViewPropertyAnimator mBarAnimator; - private Handler mHideHandler = new Handler(); - - private UndoListener mUndoListener; - - // State objects - private Parcelable mUndoToken; - private CharSequence mUndoMessage; - - public interface UndoListener { - void onUndo(Parcelable token); - } - - public UndoBarController(View undoBarView, UndoListener undoListener) { - mBarView = undoBarView; - mBarAnimator = animate(mBarView); - mUndoListener = undoListener; - - mMessageView = (TextView) mBarView.findViewById(R.id.undobar_message); - mBarView.findViewById(R.id.undobar_button) - .setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - hideUndoBar(false); - mUndoListener.onUndo(mUndoToken); - } - }); - - hideUndoBar(true); - } - - public void showUndoBar(boolean immediate, CharSequence message, Parcelable undoToken) { - mUndoToken = undoToken; - mUndoMessage = message; - mMessageView.setText(mUndoMessage); - - mHideHandler.removeCallbacks(mHideRunnable); - mHideHandler.postDelayed(mHideRunnable, - mBarView.getResources().getInteger(R.integer.undobar_hide_delay)); - - mBarView.setVisibility(View.VISIBLE); - if (immediate) { - ViewHelper.setAlpha(mBarView, 1); - } else { - mBarAnimator.cancel(); - mBarAnimator - .alpha(1) - .setDuration( - mBarView.getResources() - .getInteger(android.R.integer.config_shortAnimTime)) - .setListener(null); - } - } - - public void hideUndoBar(boolean immediate) { - mHideHandler.removeCallbacks(mHideRunnable); - if (immediate) { - mBarView.setVisibility(View.GONE); - ViewHelper.setAlpha(mBarView, 0); - mUndoMessage = null; - mUndoToken = null; - - } else { - mBarAnimator.cancel(); - mBarAnimator - .alpha(0) - .setDuration(mBarView.getResources() - .getInteger(android.R.integer.config_shortAnimTime)) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mBarView.setVisibility(View.GONE); - mUndoMessage = null; - mUndoToken = null; - } - }); - } - } - - public void onSaveInstanceState(Bundle outState) { - outState.putCharSequence("undo_message", mUndoMessage); - outState.putParcelable("undo_token", mUndoToken); - } - - public void onRestoreInstanceState(Bundle savedInstanceState) { - if (savedInstanceState != null) { - mUndoMessage = savedInstanceState.getCharSequence("undo_message"); - mUndoToken = savedInstanceState.getParcelable("undo_token"); - - if (mUndoToken != null || !TextUtils.isEmpty(mUndoMessage)) { - showUndoBar(true, mUndoMessage, mUndoToken); - } - } - } - - private Runnable mHideRunnable = new Runnable() { - @Override - public void run() { - hideUndoBar(false); - } - }; -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java index 3b791f444..26dd2ec4c 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java @@ -417,8 +417,8 @@ public abstract class PlaybackController { pauseResource = res.getResourceId(1, R.drawable.ic_pause_grey600_36dp); res.recycle(); } else { - playResource = R.drawable.ic_action_play_over_video; - pauseResource = R.drawable.ic_action_pause_over_video; + playResource = R.drawable.ic_av_play_circle_outline_80dp; + pauseResource = R.drawable.ic_av_pause_circle_outline_80dp; } switch (status) { diff --git a/core/src/main/res/drawable-hdpi/ic_action_pause_over_video.png b/core/src/main/res/drawable-hdpi/ic_action_pause_over_video.png Binary files differdeleted file mode 100755 index 64b07728f..000000000 --- a/core/src/main/res/drawable-hdpi/ic_action_pause_over_video.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_action_play_over_video.png b/core/src/main/res/drawable-hdpi/ic_action_play_over_video.png Binary files differdeleted file mode 100755 index a364ca7c2..000000000 --- a/core/src/main/res/drawable-hdpi/ic_action_play_over_video.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_av_pause_circle_outline_80dp.png b/core/src/main/res/drawable-hdpi/ic_av_pause_circle_outline_80dp.png Binary files differnew file mode 100644 index 000000000..6f9df0934 --- /dev/null +++ b/core/src/main/res/drawable-hdpi/ic_av_pause_circle_outline_80dp.png diff --git a/core/src/main/res/drawable-hdpi/ic_av_play_circle_outline_80dp.png b/core/src/main/res/drawable-hdpi/ic_av_play_circle_outline_80dp.png Binary files differnew file mode 100644 index 000000000..bddb0b024 --- /dev/null +++ b/core/src/main/res/drawable-hdpi/ic_av_play_circle_outline_80dp.png diff --git a/core/src/main/res/drawable-mdpi/ic_action_pause_over_video.png b/core/src/main/res/drawable-mdpi/ic_action_pause_over_video.png Binary files differdeleted file mode 100755 index f478ac321..000000000 --- a/core/src/main/res/drawable-mdpi/ic_action_pause_over_video.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_action_play_over_video.png b/core/src/main/res/drawable-mdpi/ic_action_play_over_video.png Binary files differdeleted file mode 100755 index 835ff3636..000000000 --- a/core/src/main/res/drawable-mdpi/ic_action_play_over_video.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_av_pause_circle_outline_80dp.png b/core/src/main/res/drawable-mdpi/ic_av_pause_circle_outline_80dp.png Binary files differnew file mode 100644 index 000000000..08c523d48 --- /dev/null +++ b/core/src/main/res/drawable-mdpi/ic_av_pause_circle_outline_80dp.png diff --git a/core/src/main/res/drawable-mdpi/ic_av_play_circle_outline_80dp.png b/core/src/main/res/drawable-mdpi/ic_av_play_circle_outline_80dp.png Binary files differnew file mode 100644 index 000000000..27738aacb --- /dev/null +++ b/core/src/main/res/drawable-mdpi/ic_av_play_circle_outline_80dp.png diff --git a/core/src/main/res/drawable-v21/overlay_button_circle_background.xml b/core/src/main/res/drawable-v21/overlay_button_circle_background.xml new file mode 100644 index 000000000..c121690df --- /dev/null +++ b/core/src/main/res/drawable-v21/overlay_button_circle_background.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <gradient + android:type="radial" + android:gradientRadius="37.5%p" + android:startColor="#000000" + android:endColor="@android:color/transparent"/> +</shape>
\ No newline at end of file diff --git a/core/src/main/res/drawable-xhdpi/ic_action_pause_over_video.png b/core/src/main/res/drawable-xhdpi/ic_action_pause_over_video.png Binary files differdeleted file mode 100755 index b0777a023..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_action_pause_over_video.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_action_play_over_video.png b/core/src/main/res/drawable-xhdpi/ic_action_play_over_video.png Binary files differdeleted file mode 100755 index 24331a48c..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_action_play_over_video.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_av_pause_circle_outline_80dp.png b/core/src/main/res/drawable-xhdpi/ic_av_pause_circle_outline_80dp.png Binary files differnew file mode 100644 index 000000000..3288241e7 --- /dev/null +++ b/core/src/main/res/drawable-xhdpi/ic_av_pause_circle_outline_80dp.png diff --git a/core/src/main/res/drawable-xhdpi/ic_av_play_circle_outline_80dp.png b/core/src/main/res/drawable-xhdpi/ic_av_play_circle_outline_80dp.png Binary files differnew file mode 100644 index 000000000..db7b695e9 --- /dev/null +++ b/core/src/main/res/drawable-xhdpi/ic_av_play_circle_outline_80dp.png diff --git a/core/src/main/res/drawable-xxhdpi/ic_action_pause_over_video.png b/core/src/main/res/drawable-xxhdpi/ic_action_pause_over_video.png Binary files differdeleted file mode 100755 index fa85601cf..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_action_pause_over_video.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_action_play_over_video.png b/core/src/main/res/drawable-xxhdpi/ic_action_play_over_video.png Binary files differdeleted file mode 100755 index 121be211e..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_action_play_over_video.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_av_pause_circle_outline_80dp.png b/core/src/main/res/drawable-xxhdpi/ic_av_pause_circle_outline_80dp.png Binary files differnew file mode 100644 index 000000000..48e28102a --- /dev/null +++ b/core/src/main/res/drawable-xxhdpi/ic_av_pause_circle_outline_80dp.png diff --git a/core/src/main/res/drawable-xxhdpi/ic_av_play_circle_outline_80dp.png b/core/src/main/res/drawable-xxhdpi/ic_av_play_circle_outline_80dp.png Binary files differnew file mode 100644 index 000000000..b5918c0f1 --- /dev/null +++ b/core/src/main/res/drawable-xxhdpi/ic_av_play_circle_outline_80dp.png diff --git a/core/src/main/res/values-da/strings.xml b/core/src/main/res/values-da/strings.xml index 4f7ea5cf9..8003f93c0 100644 --- a/core/src/main/res/values-da/strings.xml +++ b/core/src/main/res/values-da/strings.xml @@ -17,7 +17,7 @@ <string name="downloads_completed_label">Fuldført</string> <string name="downloads_log_label">Log</string> <string name="cancel_download_label">Annuller Download</string> - <string name="playback_history_label">Afspilnings historik</string> + <string name="playback_history_label">Afspilningshistorik</string> <string name="gpodnet_main_label">gpodder.net</string> <string name="gpodnet_auth_label">gpodder.net login</string> <!--New episodes fragment--> diff --git a/core/src/main/res/values-it-rIT/strings.xml b/core/src/main/res/values-it-rIT/strings.xml index b91f1a5fd..4bd82db52 100644 --- a/core/src/main/res/values-it-rIT/strings.xml +++ b/core/src/main/res/values-it-rIT/strings.xml @@ -3,24 +3,35 @@ <!--Activitiy and fragment titles--> <string name="app_name">AntennaPod</string> <string name="feeds_label">Feed</string> + <string name="add_feed_label">Aggiungi un podcast</string> <string name="podcasts_label">PODCAST</string> <string name="episodes_label">EPISODI</string> + <string name="new_episodes_label">Episodi nuovi</string> + <string name="all_episodes_label">Tutti gli episodi</string> <string name="new_label">Nuovo</string> <string name="waiting_list_label">Lista d\'attesa</string> <string name="settings_label">Impostazioni</string> <string name="add_new_feed_label">Aggiungi podcast</string> <string name="downloads_label">Download</string> + <string name="downloads_running_label">In esecuzione</string> + <string name="downloads_completed_label">Completati</string> + <string name="downloads_log_label">Registro</string> <string name="cancel_download_label">Annulla download</string> <string name="playback_history_label">Storico delle riproduzioni</string> <string name="gpodnet_main_label">gpodder.net</string> <string name="gpodnet_auth_label">gpodder.net login</string> <!--New episodes fragment--> + <string name="recently_published_episodes_label">Pubblicati di recente</string> + <string name="episode_filter_label">Mostra solo gli episodi nuovi</string> <!--Main activity--> + <string name="drawer_open">Apri il menù</string> + <string name="drawer_close">Chiudi il menù</string> <!--Webview actions--> <string name="open_in_browser_label">Apri nel browser</string> <string name="copy_url_label">Copia URL</string> <string name="share_url_label">Condividi URL</string> <string name="copied_url_msg">URL copiato negli appunti</string> + <string name="go_to_position_label">Vai a questa posizione</string> <!--Playback history--> <string name="clear_history_label">Cancella lo storico</string> <!--Other--> @@ -49,10 +60,15 @@ <string name="auto_download_label">Includi nei download automatici</string> <!--'Add Feed' Activity labels--> <string name="feedurl_label">URL del feed</string> + <string name="etxtFeedurlHint">URL del feed o del sito web</string> <string name="txtvfeedurl_label">Aggiungi un Podcast tramite URL</string> + <string name="podcastdirectories_label">Trova un podcast nella directory</string> + <string name="browse_gpoddernet_label">Esplora gpodder.net</string> <!--Actions on feeds--> <string name="mark_all_read_label">Segna tutti come letti</string> + <string name="mark_all_read_msg">Segnati tutti gli episodi come letti</string> <string name="show_info_label">Informazioni</string> + <string name="remove_feed_label">Rimuovi un podcast</string> <string name="share_link_label">Condividi il link al sito</string> <string name="share_source_label">Condividi il link al feed</string> <string name="feed_delete_confirmation_msg">Per favore conferma la cancellazione di questo feed e di TUTTI gli episodi collegati che sono stati precedentemente scaricati.</string> @@ -61,8 +77,10 @@ <string name="download_label">Download</string> <string name="play_label">Riproduci</string> <string name="pause_label">Pausa</string> + <string name="stop_label">Ferma</string> <string name="stream_label">Stream</string> <string name="remove_label">Rimuovi</string> + <string name="remove_episode_lable">Rimuovi l\'episodio</string> <string name="mark_read_label">Segna come letto</string> <string name="mark_unread_label">Segna come non letto</string> <string name="add_to_queue_label">Aggiungi alla coda</string> @@ -84,6 +102,7 @@ <string name="download_error_unsupported_type">Tipo di feed non supportato</string> <string name="download_error_connection_error">Errore di connessione</string> <string name="download_error_unknown_host">Host sconosciuto</string> + <string name="download_error_unauthorized">Errore di autenticazione</string> <string name="cancel_all_downloads_label">Annulla tutti i download</string> <string name="download_cancelled_msg">Download annullato</string> <string name="download_report_title">Download completati</string> @@ -92,6 +111,7 @@ <string name="download_error_request_error">Request error</string> <string name="download_error_db_access">Errore di accesso al database</string> <string name="downloads_left">\u0020Download rimasti</string> + <string name="downloads_processing">Elaborazione dei download in corso</string> <string name="download_notification_title">Download podcast in corso</string> <string name="download_report_content">%1$d download con successo, %2$d ko</string> <string name="download_log_title_unknown">Titolo sconosciuto</string> @@ -99,6 +119,7 @@ <string name="download_type_media">Media file</string> <string name="download_type_image">Immagine</string> <string name="download_request_error_dialog_message_prefix">Rilevato errore durante il download del file:\u0020</string> + <string name="authentication_notification_title">Autenticazione richiesta</string> <!--Mediaplayer messages--> <string name="player_error_msg">Errore!</string> <string name="player_stopped_msg">Nessun media in riproduzione</string> @@ -189,6 +210,7 @@ <string name="pref_playback_speed_sum">Personalizza le velocità disponibili per la riproduzione audio a velocità variabile</string> <string name="pref_gpodnet_sethostname_title">Imposta l\'hostname</string> <string name="pref_gpodnet_sethostname_use_default_host">Usa l\'host di default</string> + <string name="pref_expandNotify_title">Espandi le notifiche</string> <!--Auto-Flattr dialog--> <!--Search--> <string name="search_hint">Ricerca per Feed o Episodi</string> @@ -221,6 +243,9 @@ <string name="sleep_timer_label">Timer di spegnimento</string> <string name="time_left_label">Tempo residuo:\u0020</string> <string name="time_dialog_invalid_input">Input non valido, il campo deve essere un numero intero.</string> + <string name="time_unit_seconds">secondi</string> + <string name="time_unit_minutes">minuti</string> + <string name="time_unit_hours">ore</string> <!--gpodder.net--> <string name="gpodnet_taglist_header">CATEGORIE</string> <string name="gpodnet_toplist_header">TOP PODCAST</string> @@ -282,6 +307,9 @@ <string name="status_unread_label">L\'oggetto è nuovo</string> <string name="in_queue_label">L\'episodio è in coda</string> <string name="new_episodes_count_label">Numero dei nuovi episodi</string> + <string name="drag_handle_content_description">Trascina per cambiare la posizione di questo oggetto</string> + <string name="load_next_page_label">Carica la pagina successiva</string> <!--Feed information screen--> + <string name="authentication_label">Autenticazione</string> <!--AntennaPodSP--> </resources> diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b6dc96bf1..5909f8dfb 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sun Oct 12 21:44:21 CEST 2014 +#Fri Nov 28 16:00:13 CET 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip |