Merge branch 'develop'
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
private WebView webview;
|
||||
private LinearLayout webviewContainer;
|
||||
|
||||
@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
|
||||
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
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -161,11 +161,6 @@ public class ItemDescriptionFragment extends Fragment {
|
|||
return webvDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
|
@ -191,6 +186,10 @@ public class ItemDescriptionFragment extends Fragment {
|
|||
if (webViewLoader != null) {
|
||||
webViewLoader.cancel(true);
|
||||
}
|
||||
if (webvDescription != null) {
|
||||
webvDescription.removeAllViews();
|
||||
webvDescription.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
|
|
|
@ -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" >
|
||||
|
|
|
@ -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:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_weight="1"
|
||||
android:id="@+id/butAction1"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
tools:ignore="ContentDescription"/>
|
||||
|
||||
<ImageButton
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_weight="1"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/butAction2"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
tools:ignore="ContentDescription"/>
|
||||
|
||||
<ImageButton
|
||||
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"/>
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/butMoreActions"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_weight="1"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
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>
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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'
|
||||
}
|
|
@ -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'
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -109,6 +111,36 @@ public class MediaPlayer {
|
|||
return list.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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";
|
||||
private static final String TAG = "FeedUpdateReceiver";
|
||||
|
||||
@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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@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);
|
||||
private boolean connectedToWifi(Context context) {
|
||||
ConnectivityManager connManager = (ConnectivityManager) context
|
||||
.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo mWifi = connManager
|
||||
.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
|
||||
|
||||
return mWifi.isConnected();
|
||||
}
|
||||
return mWifi.isConnected();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
long imageIndex = itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_IMAGE);
|
||||
FeedImage image = null;
|
||||
if (imageIndex != 0) {
|
||||
image = getFeedImage(adapter, imageIndex);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
if (imageIndex != 0) {
|
||||
item.setImage(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();
|
||||
}
|
||||
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)
|
||||
|
@ -736,6 +701,63 @@ public final class DBReader {
|
|||
adapter.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -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)),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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) {
|
||||
|
|
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.8 KiB |
|
@ -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>
|
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 7.9 KiB |
After Width: | Height: | Size: 8.0 KiB |
|
@ -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-->
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|