diff options
author | daniel oeh <daniel.oeh@gmail.com> | 2013-08-04 17:28:29 +0200 |
---|---|---|
committer | daniel oeh <daniel.oeh@gmail.com> | 2013-08-04 17:28:29 +0200 |
commit | 355fc8114f61ed2ecde8f118c4d30d209ceb6198 (patch) | |
tree | d8b78540703fdbec8c0c2a02c11c5d6580ed02e9 /src/de/danoeh | |
parent | 9f36cecf4bbcd4a8fe1d199c25758096b22e08f6 (diff) | |
download | AntennaPod-355fc8114f61ed2ecde8f118c4d30d209ceb6198.zip |
Ported playback classes to DB* classes
Diffstat (limited to 'src/de/danoeh')
-rw-r--r-- | src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java | 1 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/feed/FeedItem.java | 576 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/feed/FeedMedia.java | 721 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java | 848 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/storage/DBReader.java | 15 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/storage/DBWriter.java | 14 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/storage/PodDBAdapter.java | 11 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/util/playback/ExternalMedia.java | 10 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/util/playback/Playable.java | 16 |
9 files changed, 1139 insertions, 1073 deletions
diff --git a/src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java b/src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java index 9730c805c..4d4a3d260 100644 --- a/src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java +++ b/src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java @@ -11,7 +11,6 @@ import com.actionbarsherlock.view.MenuItem; import de.danoeh.antennapod.AppConfig; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.feed.FeedManager; import de.danoeh.antennapod.fragment.PlaybackHistoryFragment; import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.storage.DBWriter; diff --git a/src/de/danoeh/antennapod/feed/FeedItem.java b/src/de/danoeh/antennapod/feed/FeedItem.java index c7b130763..67ffcb1c6 100644 --- a/src/de/danoeh/antennapod/feed/FeedItem.java +++ b/src/de/danoeh/antennapod/feed/FeedItem.java @@ -4,291 +4,311 @@ import java.io.InputStream; import java.lang.ref.SoftReference; import java.util.Date; import java.util.List; +import java.util.concurrent.Callable; +import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.asynctask.ImageLoader; +import de.danoeh.antennapod.storage.DBReader; +import de.danoeh.antennapod.util.ShownotesProvider; /** * Data Object for a XML message - * + * * @author daniel - * */ public class FeedItem extends FeedComponent implements - ImageLoader.ImageWorkerTaskResource { - - /** The id/guid that can be found in the rss/atom feed. Might not be set. */ - private String itemIdentifier; - private String title; - /** - * The description of a feeditem. This field should only be set by the - * parser. - */ - private String description; - /** - * The content of the content-encoded tag of a feeditem. This field should - * only be set by the parser. - */ - private String contentEncoded; - - private SoftReference<String> cachedDescription; - private SoftReference<String> cachedContentEncoded; - - private String link; - private Date pubDate; - private FeedMedia media; - - private Feed feed; - private long feedId; - - private boolean read; - private String paymentLink; - private List<Chapter> chapters; - - public FeedItem() { - this.read = true; - } - - public void updateFromOther(FeedItem other) { - super.updateFromOther(other); - if (other.title != null) { - title = other.title; - } - if (other.getDescription() != null) { - description = other.getDescription(); - } - if (other.getContentEncoded() != null) { - contentEncoded = other.contentEncoded; - } - if (other.link != null) { - link = other.link; - } - if (other.pubDate != null && other.pubDate != pubDate) { - pubDate = other.pubDate; - } - if (other.media != null) { - if (media == null) { - media = other.media; - } else if (media.compareWithOther(other)) { - media.updateFromOther(other); - } - } - if (other.paymentLink != null) { - paymentLink = other.paymentLink; - } - if (other.chapters != null) { - if (chapters == null) { - chapters = other.chapters; - } - } - } - - /** - * Moves the 'description' and 'contentEncoded' field of feeditem to their - * SoftReference fields. - */ - protected void cacheDescriptions() { - if (description != null) { - cachedDescription = new SoftReference<String>(description); - } - if (contentEncoded != null) { - cachedContentEncoded = new SoftReference<String>(contentEncoded); - } - description = null; - contentEncoded = null; - } - - /** - * Returns the value that uniquely identifies this FeedItem. If the - * itemIdentifier attribute is not null, it will be returned. Else it will - * try to return the title. If the title is not given, it will use the link - * of the entry. - * */ - public String getIdentifyingValue() { - if (itemIdentifier != null) { - return itemIdentifier; - } else if (title != null) { - return title; - } else { - return link; - } - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDescription() { - if (description == null && cachedDescription != null) { - return cachedDescription.get(); - } - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getLink() { - return link; - } - - public void setLink(String link) { - this.link = link; - } - - public Date getPubDate() { - return pubDate; - } - - public void setPubDate(Date pubDate) { - this.pubDate = pubDate; - } - - public FeedMedia getMedia() { - return media; - } - - public void setMedia(FeedMedia media) { - this.media = media; - } - - public Feed getFeed() { - return feed; - } - - public void setFeed(Feed feed) { - this.feed = feed; - } - - public boolean isRead() { - return read || isInProgress(); - } - - public void setRead(boolean read) { - this.read = read; - } - - private boolean isInProgress() { - return (media != null && media.isInProgress()); - } - - public String getContentEncoded() { - if (contentEncoded == null && cachedContentEncoded != null) { - return cachedContentEncoded.get(); - - } - return contentEncoded; - } - - public void setContentEncoded(String contentEncoded) { - this.contentEncoded = contentEncoded; - } - - public String getPaymentLink() { - return paymentLink; - } - - public void setPaymentLink(String paymentLink) { - this.paymentLink = paymentLink; - } - - public List<Chapter> getChapters() { - return chapters; - } - - public void setChapters(List<Chapter> chapters) { - this.chapters = chapters; - } - - public String getItemIdentifier() { - return itemIdentifier; - } - - public void setItemIdentifier(String itemIdentifier) { - this.itemIdentifier = itemIdentifier; - } - - public boolean hasMedia() { - return media != null; - } - - private boolean isPlaying() { - if (media != null) { - return media.isPlaying(); - } - return false; - } - - public void setCachedDescription(String d) { - cachedDescription = new SoftReference<String>(d); - } - - public void setCachedContentEncoded(String c) { - cachedContentEncoded = new SoftReference<String>(c); - } - - public enum State { - NEW, IN_PROGRESS, READ, PLAYING - } - - public State getState() { - if (hasMedia()) { - if (isPlaying()) { - return State.PLAYING; - } - if (isInProgress()) { - return State.IN_PROGRESS; - } - } - return (isRead() ? State.READ : State.NEW); - } - - @Override - public InputStream openImageInputStream() { - InputStream out = null; - if (hasMedia()) { - out = media.openImageInputStream(); - } - if (out == null && feed.getImage() != null) { - out = feed.getImage().openImageInputStream(); - } - return out; - } - - @Override - public InputStream reopenImageInputStream(InputStream input) { - InputStream out = null; - if (hasMedia()) { - out = media.reopenImageInputStream(input); - } - if (out == null && feed.getImage() != null) { - out = feed.getImage().reopenImageInputStream(input); - } - return out; - } - - @Override - public String getImageLoaderCacheKey() { - String out = null; - if (hasMedia()) { - out = media.getImageLoaderCacheKey(); - } - if (out == null && feed.getImage() != null) { - out = feed.getImage().getImageLoaderCacheKey(); - } - return out; - } - - public long getFeedId() { - return feedId; - } - - public void setFeedId(long feedId) { - this.feedId = feedId; - } + ImageLoader.ImageWorkerTaskResource, ShownotesProvider { + + /** + * The id/guid that can be found in the rss/atom feed. Might not be set. + */ + private String itemIdentifier; + private String title; + /** + * The description of a feeditem. This field should only be set by the + * parser. + */ + private String description; + /** + * The content of the content-encoded tag of a feeditem. This field should + * only be set by the parser. + */ + private String contentEncoded; + + private SoftReference<String> cachedDescription; + private SoftReference<String> cachedContentEncoded; + + private String link; + private Date pubDate; + private FeedMedia media; + + private Feed feed; + private long feedId; + + private boolean read; + private String paymentLink; + private List<Chapter> chapters; + + public FeedItem() { + this.read = true; + } + + public void updateFromOther(FeedItem other) { + super.updateFromOther(other); + if (other.title != null) { + title = other.title; + } + if (other.getDescription() != null) { + description = other.getDescription(); + } + if (other.getContentEncoded() != null) { + contentEncoded = other.contentEncoded; + } + if (other.link != null) { + link = other.link; + } + if (other.pubDate != null && other.pubDate != pubDate) { + pubDate = other.pubDate; + } + if (other.media != null) { + if (media == null) { + media = other.media; + } else if (media.compareWithOther(other)) { + media.updateFromOther(other); + } + } + if (other.paymentLink != null) { + paymentLink = other.paymentLink; + } + if (other.chapters != null) { + if (chapters == null) { + chapters = other.chapters; + } + } + } + + /** + * Moves the 'description' and 'contentEncoded' field of feeditem to their + * SoftReference fields. + */ + protected void cacheDescriptions() { + if (description != null) { + cachedDescription = new SoftReference<String>(description); + } + if (contentEncoded != null) { + cachedContentEncoded = new SoftReference<String>(contentEncoded); + } + description = null; + contentEncoded = null; + } + + /** + * Returns the value that uniquely identifies this FeedItem. If the + * itemIdentifier attribute is not null, it will be returned. Else it will + * try to return the title. If the title is not given, it will use the link + * of the entry. + */ + public String getIdentifyingValue() { + if (itemIdentifier != null) { + return itemIdentifier; + } else if (title != null) { + return title; + } else { + return link; + } + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + if (description == null && cachedDescription != null) { + return cachedDescription.get(); + } + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getLink() { + return link; + } + + public void setLink(String link) { + this.link = link; + } + + public Date getPubDate() { + return pubDate; + } + + public void setPubDate(Date pubDate) { + this.pubDate = pubDate; + } + + public FeedMedia getMedia() { + return media; + } + + public void setMedia(FeedMedia media) { + this.media = media; + } + + public Feed getFeed() { + return feed; + } + + public void setFeed(Feed feed) { + this.feed = feed; + } + + public boolean isRead() { + return read || isInProgress(); + } + + public void setRead(boolean read) { + this.read = read; + } + + private boolean isInProgress() { + return (media != null && media.isInProgress()); + } + + public String getContentEncoded() { + if (contentEncoded == null && cachedContentEncoded != null) { + return cachedContentEncoded.get(); + + } + return contentEncoded; + } + + public void setContentEncoded(String contentEncoded) { + this.contentEncoded = contentEncoded; + } + + public String getPaymentLink() { + return paymentLink; + } + + public void setPaymentLink(String paymentLink) { + this.paymentLink = paymentLink; + } + + public List<Chapter> getChapters() { + return chapters; + } + + public void setChapters(List<Chapter> chapters) { + this.chapters = chapters; + } + + public String getItemIdentifier() { + return itemIdentifier; + } + + public void setItemIdentifier(String itemIdentifier) { + this.itemIdentifier = itemIdentifier; + } + + public boolean hasMedia() { + return media != null; + } + + private boolean isPlaying() { + if (media != null) { + return media.isPlaying(); + } + return false; + } + + public void setCachedDescription(String d) { + cachedDescription = new SoftReference<String>(d); + } + + public void setCachedContentEncoded(String c) { + cachedContentEncoded = new SoftReference<String>(c); + } + + @Override + public Callable<String> loadShownotes() { + return new Callable<String>() { + @Override + public String call() throws Exception { + + if (contentEncoded == null || description == null) { + DBReader.loadExtraInformationOfFeedItem(PodcastApp.getInstance(), FeedItem.this); + + } + return (contentEncoded != null) ? contentEncoded : description; + } + }; + } + + public enum State { + NEW, IN_PROGRESS, READ, PLAYING + } + + public State getState() { + if (hasMedia()) { + if (isPlaying()) { + return State.PLAYING; + } + if (isInProgress()) { + return State.IN_PROGRESS; + } + } + return (isRead() ? State.READ : State.NEW); + } + + @Override + public InputStream openImageInputStream() { + InputStream out = null; + if (hasMedia()) { + out = media.openImageInputStream(); + } + if (out == null && feed.getImage() != null) { + out = feed.getImage().openImageInputStream(); + } + return out; + } + + @Override + public InputStream reopenImageInputStream(InputStream input) { + InputStream out = null; + if (hasMedia()) { + out = media.reopenImageInputStream(input); + } + if (out == null && feed.getImage() != null) { + out = feed.getImage().reopenImageInputStream(input); + } + return out; + } + + @Override + public String getImageLoaderCacheKey() { + String out = null; + if (hasMedia()) { + out = media.getImageLoaderCacheKey(); + } + if (out == null && feed.getImage() != null) { + out = feed.getImage().getImageLoaderCacheKey(); + } + return out; + } + + public long getFeedId() { + return feedId; + } + + public void setFeedId(long feedId) { + this.feedId = feedId; + } } diff --git a/src/de/danoeh/antennapod/feed/FeedMedia.java b/src/de/danoeh/antennapod/feed/FeedMedia.java index 1368cf854..3b7a5ec4e 100644 --- a/src/de/danoeh/antennapod/feed/FeedMedia.java +++ b/src/de/danoeh/antennapod/feed/FeedMedia.java @@ -4,6 +4,7 @@ import java.io.FileInputStream; import java.io.InputStream; import java.util.Date; import java.util.List; +import java.util.concurrent.Callable; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; @@ -11,358 +12,380 @@ import android.os.Parcel; import android.os.Parcelable; import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.preferences.PlaybackPreferences; +import de.danoeh.antennapod.storage.DBReader; +import de.danoeh.antennapod.storage.DBWriter; import de.danoeh.antennapod.util.ChapterUtils; import de.danoeh.antennapod.util.playback.Playable; public class FeedMedia extends FeedFile implements Playable { - public static final int FEEDFILETYPE_FEEDMEDIA = 2; - public static final int PLAYABLE_TYPE_FEEDMEDIA = 1; - - public static final String PREF_MEDIA_ID = "FeedMedia.PrefMediaId"; - public static final String PREF_FEED_ID = "FeedMedia.PrefFeedId"; - - private int duration; - private int position; // Current position in file - private long size; // File size in Byte - private String mime_type; - private FeedItem item; - private Date playbackCompletionDate; - - public FeedMedia(FeedItem i, String download_url, long size, - String mime_type) { - super(null, download_url, false); - this.item = i; - this.size = size; - this.mime_type = mime_type; - } - - public FeedMedia(long id, FeedItem item, int duration, int position, - long size, String mime_type, String file_url, String download_url, - boolean downloaded, Date playbackCompletionDate) { - super(file_url, download_url, downloaded); - this.id = id; - this.item = item; - this.duration = duration; - this.position = position; - this.size = size; - this.mime_type = mime_type; - this.playbackCompletionDate = playbackCompletionDate; - } - - public FeedMedia(long id, FeedItem item) { - super(); - this.id = id; - this.item = item; - } - - @Override - public String getHumanReadableIdentifier() { - if (item != null && item.getTitle() != null) { - return item.getTitle(); - } else { - return download_url; - } - } - - /** Uses mimetype to determine the type of media. */ - public MediaType getMediaType() { - if (mime_type == null || mime_type.isEmpty()) { - return MediaType.UNKNOWN; - } else { - if (mime_type.startsWith("audio")) { - return MediaType.AUDIO; - } else if (mime_type.startsWith("video")) { - return MediaType.VIDEO; - } else if (mime_type.equals("application/ogg")) { - return MediaType.AUDIO; - } - } - return MediaType.UNKNOWN; - } - - public void updateFromOther(FeedMedia other) { - super.updateFromOther(other); - if (other.size > 0) { - size = other.size; - } - if (other.mime_type != null) { - mime_type = other.mime_type; - } - } - - public boolean compareWithOther(FeedMedia other) { - if (super.compareWithOther(other)) { - return true; - } - if (other.mime_type != null) { - if (mime_type == null || !mime_type.equals(other.mime_type)) { - return true; - } - } - if (other.size > 0 && other.size != size) { - return true; - } - return false; - } - - /** - * Reads playback preferences to determine whether this FeedMedia object is - * currently being played. - */ - public boolean isPlaying() { - return PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA - && PlaybackPreferences.getCurrentlyPlayingFeedMediaId() == id; - } - - @Override - public int getTypeAsInt() { - return FEEDFILETYPE_FEEDMEDIA; - } - - public int getDuration() { - return duration; - } - - public void setDuration(int duration) { - this.duration = duration; - } - - public int getPosition() { - return position; - } - - public void setPosition(int position) { - this.position = position; - } - - public long getSize() { - return size; - } - - public void setSize(long size) { - this.size = size; - } - - public String getMime_type() { - return mime_type; - } - - public void setMime_type(String mime_type) { - this.mime_type = mime_type; - } - - public FeedItem getItem() { - return item; - } - - public void setItem(FeedItem item) { - this.item = item; - } - - public Date getPlaybackCompletionDate() { - return playbackCompletionDate; - } - - public void setPlaybackCompletionDate(Date playbackCompletionDate) { - this.playbackCompletionDate = playbackCompletionDate; - } - - public boolean isInProgress() { - return (this.position > 0); - } - - public FeedImage getImage() { - if (item != null && item.getFeed() != null) { - return item.getFeed().getImage(); - } - return null; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(item.getFeed().getId()); - dest.writeLong(item.getId()); - } - - @Override - public void writeToPreferences(Editor prefEditor) { - prefEditor.putLong(PREF_FEED_ID, item.getFeed().getId()); - prefEditor.putLong(PREF_MEDIA_ID, id); - } - - @Override - public void loadMetadata() throws PlayableException { - } - - @Override - public void loadChapterMarks() { - if (getChapters() == null && !localFileAvailable()) { - ChapterUtils.loadChaptersFromStreamUrl(this); - if (getChapters() != null) { - FeedManager.getInstance().setFeedItem(PodcastApp.getInstance(), - item); - } - } - - } - - @Override - public String getEpisodeTitle() { - if (getItem().getTitle() != null) { - return getItem().getTitle(); - } else { - return getItem().getIdentifyingValue(); - } - } - - @Override - public List<Chapter> getChapters() { - return getItem().getChapters(); - } - - @Override - public String getWebsiteLink() { - return getItem().getLink(); - } - - @Override - public String getFeedTitle() { - return getItem().getFeed().getTitle(); - } - - @Override - public Object getIdentifier() { - return id; - } - - @Override - public String getLocalMediaUrl() { - return file_url; - } - - @Override - public String getStreamUrl() { - return download_url; - } - - @Override - public boolean localFileAvailable() { - return isDownloaded() && file_url != null; - } - - @Override - public boolean streamAvailable() { - return download_url != null; - } - - @Override - public void saveCurrentPosition(SharedPreferences pref, int newPosition) { - position = newPosition; - FeedManager.getInstance().setFeedMedia(PodcastApp.getInstance(), this); - } - - @Override - public void onPlaybackStart() { - } - - @Override - public void onPlaybackCompleted() { - - } - - @Override - public int getPlayableType() { - return PLAYABLE_TYPE_FEEDMEDIA; - } - - @Override - public void setChapters(List<Chapter> chapters) { - getItem().setChapters(chapters); - } - - @Override - public String getPaymentLink() { - return getItem().getPaymentLink(); - } - - @Override - public void loadShownotes(final ShownoteLoaderCallback callback) { - String contentEncoded = item.getContentEncoded(); - if (item.getDescription() == null || contentEncoded == null) { - FeedManager.getInstance().loadExtraInformationOfItem( - PodcastApp.getInstance(), item, - new FeedManager.TaskCallback<String[]>() { - @Override - public void onCompletion(String[] result) { - if (result[1] != null) { - callback.onShownotesLoaded(result[1]); - } else { - callback.onShownotesLoaded(result[0]); - - } - - } - }); - } else { - callback.onShownotesLoaded(contentEncoded); - } - } - - public static final Parcelable.Creator<FeedMedia> CREATOR = new Parcelable.Creator<FeedMedia>() { - public FeedMedia createFromParcel(Parcel in) { - long feedId = in.readLong(); - long itemId = in.readLong(); - FeedItem item = FeedManager.getInstance().getFeedItem(itemId, - feedId); - if (item != null) { - return item.getMedia(); - } else { - return null; - } - } - - public FeedMedia[] newArray(int size) { - return new FeedMedia[size]; - } - }; - - @Override - public InputStream openImageInputStream() { - InputStream out = new Playable.DefaultPlayableImageLoader(this) - .openImageInputStream(); - if (out == null) { - if (item.getFeed().getImage() != null) { - return item.getFeed().getImage().openImageInputStream(); - } - } - return out; - } - - @Override - public String getImageLoaderCacheKey() { - String out = new Playable.DefaultPlayableImageLoader(this) - .getImageLoaderCacheKey(); - if (out == null) { - if (item.getFeed().getImage() != null) { - return item.getFeed().getImage().getImageLoaderCacheKey(); - } - } - return out; - } - - @Override - public InputStream reopenImageInputStream(InputStream input) { - if (input instanceof FileInputStream) { - return item.getFeed().getImage().reopenImageInputStream(input); - } else { - return new Playable.DefaultPlayableImageLoader(this) - .reopenImageInputStream(input); - } - } + public static final int FEEDFILETYPE_FEEDMEDIA = 2; + public static final int PLAYABLE_TYPE_FEEDMEDIA = 1; + + public static final String PREF_MEDIA_ID = "FeedMedia.PrefMediaId"; + public static final String PREF_FEED_ID = "FeedMedia.PrefFeedId"; + + private int duration; + private int position; // Current position in file + private long size; // File size in Byte + private String mime_type; + private volatile FeedItem item; + private Date playbackCompletionDate; + + /* Used for loading item when restoring from parcel. */ + private long itemID; + + public FeedMedia(FeedItem i, String download_url, long size, + String mime_type) { + super(null, download_url, false); + this.item = i; + this.size = size; + this.mime_type = mime_type; + } + + public FeedMedia(long id, FeedItem item, int duration, int position, + long size, String mime_type, String file_url, String download_url, + boolean downloaded, Date playbackCompletionDate) { + super(file_url, download_url, downloaded); + this.id = id; + this.item = item; + this.duration = duration; + this.position = position; + this.size = size; + this.mime_type = mime_type; + this.playbackCompletionDate = playbackCompletionDate; + } + + public FeedMedia(long id, FeedItem item) { + super(); + this.id = id; + this.item = item; + } + + @Override + public String getHumanReadableIdentifier() { + if (item != null && item.getTitle() != null) { + return item.getTitle(); + } else { + return download_url; + } + } + + /** + * Uses mimetype to determine the type of media. + */ + public MediaType getMediaType() { + if (mime_type == null || mime_type.isEmpty()) { + return MediaType.UNKNOWN; + } else { + if (mime_type.startsWith("audio")) { + return MediaType.AUDIO; + } else if (mime_type.startsWith("video")) { + return MediaType.VIDEO; + } else if (mime_type.equals("application/ogg")) { + return MediaType.AUDIO; + } + } + return MediaType.UNKNOWN; + } + + public void updateFromOther(FeedMedia other) { + super.updateFromOther(other); + if (other.size > 0) { + size = other.size; + } + if (other.mime_type != null) { + mime_type = other.mime_type; + } + } + + public boolean compareWithOther(FeedMedia other) { + if (super.compareWithOther(other)) { + return true; + } + if (other.mime_type != null) { + if (mime_type == null || !mime_type.equals(other.mime_type)) { + return true; + } + } + if (other.size > 0 && other.size != size) { + return true; + } + return false; + } + + /** + * Reads playback preferences to determine whether this FeedMedia object is + * currently being played. + */ + public boolean isPlaying() { + return PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA + && PlaybackPreferences.getCurrentlyPlayingFeedMediaId() == id; + } + + @Override + public int getTypeAsInt() { + return FEEDFILETYPE_FEEDMEDIA; + } + + public int getDuration() { + return duration; + } + + public void setDuration(int duration) { + this.duration = duration; + } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + } + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } + + public String getMime_type() { + return mime_type; + } + + public void setMime_type(String mime_type) { + this.mime_type = mime_type; + } + + public FeedItem getItem() { + return item; + } + + public void setItem(FeedItem item) { + this.item = item; + } + + public Date getPlaybackCompletionDate() { + return playbackCompletionDate; + } + + public void setPlaybackCompletionDate(Date playbackCompletionDate) { + this.playbackCompletionDate = playbackCompletionDate; + } + + public boolean isInProgress() { + return (this.position > 0); + } + + public FeedImage getImage() { + if (item != null && item.getFeed() != null) { + return item.getFeed().getImage(); + } + return null; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(id); + dest.writeLong(item.getId()); + + dest.writeInt(duration); + dest.writeInt(position); + dest.writeLong(size); + dest.writeString(mime_type); + dest.writeString(file_url); + dest.writeString(download_url); + dest.writeByte((byte) ((downloaded) ? 1 : 0)); + dest.writeLong((playbackCompletionDate != null) ? playbackCompletionDate.getTime() : 0); + } + + @Override + public void writeToPreferences(Editor prefEditor) { + prefEditor.putLong(PREF_FEED_ID, item.getFeed().getId()); + prefEditor.putLong(PREF_MEDIA_ID, id); + } + + @Override + public void loadMetadata() throws PlayableException { + if (item == null && itemID != 0) { + item = DBReader.getFeedItem(PodcastApp.getInstance(), itemID); + } + } + + @Override + public void loadChapterMarks() { + if (getChapters() == null && !localFileAvailable()) { + ChapterUtils.loadChaptersFromStreamUrl(this); + if (getChapters() != null) { + FeedManager.getInstance().setFeedItem(PodcastApp.getInstance(), + item); + } + } + + } + + @Override + public String getEpisodeTitle() { + if (item == null) { + return null; + } + if (getItem().getTitle() != null) { + return getItem().getTitle(); + } else { + return getItem().getIdentifyingValue(); + } + } + + @Override + public List<Chapter> getChapters() { + if (item == null) { + return null; + } + return getItem().getChapters(); + } + + @Override + public String getWebsiteLink() { + if (item == null) { + return null; + } + return getItem().getLink(); + } + + @Override + public String getFeedTitle() { + if (item == null) { + return null; + } + return getItem().getFeed().getTitle(); + } + + @Override + public Object getIdentifier() { + return id; + } + + @Override + public String getLocalMediaUrl() { + return file_url; + } + + @Override + public String getStreamUrl() { + return download_url; + } + + @Override + public boolean localFileAvailable() { + return isDownloaded() && file_url != null; + } + + @Override + public boolean streamAvailable() { + return download_url != null; + } + + @Override + public void saveCurrentPosition(SharedPreferences pref, int newPosition) { + position = newPosition; + DBWriter.setFeedMediaPosition(PodcastApp.getInstance(), this); + } + + @Override + public void onPlaybackStart() { + } + + @Override + public void onPlaybackCompleted() { + + } + + @Override + public int getPlayableType() { + return PLAYABLE_TYPE_FEEDMEDIA; + } + + @Override + public void setChapters(List<Chapter> chapters) { + getItem().setChapters(chapters); + } + + @Override + public String getPaymentLink() { + return getItem().getPaymentLink(); + } + + @Override + public Callable<String> loadShownotes() { + return new Callable<String>() { + @Override + public String call() throws Exception { + if (item == null) { + item = DBReader.getFeedItem(PodcastApp.getInstance(), itemID); + } + if (item.getContentEncoded() == null || item.getDescription() == null) { + DBReader.loadExtraInformationOfFeedItem(PodcastApp.getInstance(), item); + + } + return (item.getContentEncoded() != null) ? item.getContentEncoded() : item.getDescription(); + } + }; + } + + public static final Parcelable.Creator<FeedMedia> CREATOR = new Parcelable.Creator<FeedMedia>() { + public FeedMedia createFromParcel(Parcel in) { + final long id = in.readLong(); + final long itemID = in.readLong(); + FeedMedia result = new FeedMedia(id, null, in.readInt(), in.readInt(), in.readLong(), in.readString(), in.readString(), + in.readString(), in.readByte() != 0, new Date(in.readLong())); + result.itemID = itemID; + return result; + } + + public FeedMedia[] newArray(int size) { + return new FeedMedia[size]; + } + }; + + @Override + public InputStream openImageInputStream() { + InputStream out = new Playable.DefaultPlayableImageLoader(this) + .openImageInputStream(); + if (out == null) { + if (item.getFeed().getImage() != null) { + return item.getFeed().getImage().openImageInputStream(); + } + } + return out; + } + + @Override + public String getImageLoaderCacheKey() { + String out = new Playable.DefaultPlayableImageLoader(this) + .getImageLoaderCacheKey(); + if (out == null) { + if (item.getFeed().getImage() != null) { + return item.getFeed().getImage().getImageLoaderCacheKey(); + } + } + return out; + } + + @Override + public InputStream reopenImageInputStream(InputStream input) { + if (input instanceof FileInputStream) { + return item.getFeed().getImage().reopenImageInputStream(input); + } else { + return new Playable.DefaultPlayableImageLoader(this) + .reopenImageInputStream(input); + } + } } diff --git a/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java index 10f43718f..3d74653f3 100644 --- a/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java +++ b/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java @@ -1,5 +1,9 @@ package de.danoeh.antennapod.fragment; +import de.danoeh.antennapod.feed.FeedItem; +import de.danoeh.antennapod.feed.FeedMedia; +import de.danoeh.antennapod.storage.DBReader; +import de.danoeh.antennapod.util.ShownotesProvider; import org.apache.commons.lang3.StringEscapeUtils; import android.annotation.SuppressLint; @@ -30,439 +34,427 @@ import android.widget.Toast; import com.actionbarsherlock.app.SherlockFragment; import de.danoeh.antennapod.AppConfig; -import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.feed.FeedItem; -import de.danoeh.antennapod.feed.FeedManager; import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.util.ShareUtils; import de.danoeh.antennapod.util.playback.Playable; -/** Displays the description of a Playable object in a Webview. */ +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; + +/** + * Displays the description of a Playable object in a Webview. + */ public class ItemDescriptionFragment extends SherlockFragment { - private static final String TAG = "ItemDescriptionFragment"; - - private static final String PREF = "ItemDescriptionFragmentPrefs"; - private static final String PREF_SCROLL_Y = "prefScrollY"; - private static final String PREF_PLAYABLE_ID = "prefPlayableId"; - - private static final String ARG_PLAYABLE = "arg.playable"; - - private static final String ARG_FEED_ID = "arg.feedId"; - private static final String ARG_FEED_ITEM_ID = "arg.feeditemId"; - private static final String ARG_SAVE_STATE = "arg.saveState"; - - private WebView webvDescription; - private Playable media; - - private FeedItem item; - - private AsyncTask<Void, Void, Void> webViewLoader; - - private String shownotes; - - /** URL that was selected via long-press. */ - private String selectedURL; - - /** - * True if Fragment should save its state (e.g. scrolling position) in a - * shared preference. - */ - private boolean saveState; - - public static ItemDescriptionFragment newInstance(Playable media, - boolean saveState) { - ItemDescriptionFragment f = new ItemDescriptionFragment(); - Bundle args = new Bundle(); - args.putParcelable(ARG_PLAYABLE, media); - args.putBoolean(ARG_SAVE_STATE, saveState); - f.setArguments(args); - return f; - } - - public static ItemDescriptionFragment newInstance(FeedItem item, - boolean saveState) { - ItemDescriptionFragment f = new ItemDescriptionFragment(); - Bundle args = new Bundle(); - args.putLong(ARG_FEED_ID, item.getFeed().getId()); - args.putLong(ARG_FEED_ITEM_ID, item.getId()); - args.putBoolean(ARG_SAVE_STATE, saveState); - f.setArguments(args); - return f; - } - - @SuppressLint("NewApi") - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - if (AppConfig.DEBUG) - Log.d(TAG, "Creating view"); - webvDescription = new WebView(getActivity()); - if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) { - if (Build.VERSION.SDK_INT >= 11 - && Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { - webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null); - } - webvDescription.setBackgroundColor(getResources().getColor( - R.color.black)); - } - webvDescription.getSettings().setUseWideViewPort(false); - webvDescription.getSettings().setLayoutAlgorithm( - LayoutAlgorithm.NARROW_COLUMNS); - webvDescription.getSettings().setLoadWithOverviewMode(true); - webvDescription.setOnLongClickListener(webViewLongClickListener); - webvDescription.setWebViewClient(new WebViewClient() { - - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - startActivity(intent); - return true; - } - - @Override - public void onPageFinished(WebView view, String url) { - super.onPageFinished(view, url); - if (AppConfig.DEBUG) - Log.d(TAG, "Page finished"); - // Restoring the scroll position might not always work - view.postDelayed(new Runnable() { - - @Override - public void run() { - restoreFromPreference(); - } - - }, 50); - } - - }); - registerForContextMenu(webvDescription); - return webvDescription; - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - if (AppConfig.DEBUG) - Log.d(TAG, "Fragment attached"); - } - - @Override - public void onDetach() { - super.onDetach(); - if (AppConfig.DEBUG) - Log.d(TAG, "Fragment detached"); - if (webViewLoader != null) { - webViewLoader.cancel(true); - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - if (AppConfig.DEBUG) - Log.d(TAG, "Fragment destroyed"); - if (webViewLoader != null) { - webViewLoader.cancel(true); - } - } - - @SuppressLint("NewApi") - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (AppConfig.DEBUG) - Log.d(TAG, "Creating fragment"); - Bundle args = getArguments(); - saveState = args.getBoolean(ARG_SAVE_STATE, false); - if (args.containsKey(ARG_PLAYABLE)) { - media = args.getParcelable(ARG_PLAYABLE); - } else if (args.containsKey(ARG_FEED_ID) - && args.containsKey(ARG_FEED_ITEM_ID)) { - long feedId = args.getLong(ARG_FEED_ID); - long itemId = args.getLong(ARG_FEED_ITEM_ID); - FeedItem f = FeedManager.getInstance().getFeedItem(itemId, feedId); - if (f != null) { - item = f; - } - } - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - if (media != null) { - media.loadShownotes(new Playable.ShownoteLoaderCallback() { - - @Override - public void onShownotesLoaded(String shownotes) { - ItemDescriptionFragment.this.shownotes = shownotes; - if (ItemDescriptionFragment.this.shownotes != null) { - startLoader(); - } - } - }); - } else if (item != null) { - if (item.getDescription() == null - || item.getContentEncoded() == null) { - FeedManager.getInstance().loadExtraInformationOfItem( - PodcastApp.getInstance(), item, - new FeedManager.TaskCallback<String[]>() { - @Override - public void onCompletion(String[] result) { - if (result[1] != null) { - shownotes = result[1]; - } else { - shownotes = result[0]; - } - if (shownotes != null) { - startLoader(); - } - - } - }); - } else { - shownotes = item.getContentEncoded(); - startLoader(); - } - } else { - Log.e(TAG, "Error in onViewCreated: Item and media were null"); - } - } - - @Override - public void onResume() { - super.onResume(); - } - - @SuppressLint("NewApi") - private void startLoader() { - webViewLoader = createLoader(); - if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { - webViewLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } else { - webViewLoader.execute(); - } - } - - /** - * Return the CSS style of the Webview. - * - * @param textColor - * the default color to use for the text in the webview. This - * value is inserted directly into the CSS String. - * */ - private String applyWebviewStyle(String textColor, String data) { - final String WEBVIEW_STYLE = "<html><head><style type=\"text/css\"> * { color: %s; font-family: Helvetica; line-height: 1.5em; font-size: 11pt; } a { font-style: normal; text-decoration: none; font-weight: normal; color: #00A8DF; } img { display: block; margin: 10 auto; max-width: %s; height: auto; } body { margin: %dpx %dpx %dpx %dpx; }</style></head><body>%s</body></html>"; - final int pageMargin = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, 8, getResources() - .getDisplayMetrics()); - return String.format(WEBVIEW_STYLE, textColor, "100%", pageMargin, - pageMargin, pageMargin, pageMargin, data); - } - - private View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() { - - @Override - public boolean onLongClick(View v) { - WebView.HitTestResult r = webvDescription.getHitTestResult(); - if (r != null - && r.getType() == WebView.HitTestResult.SRC_ANCHOR_TYPE) { - if (AppConfig.DEBUG) - Log.d(TAG, - "Link of webview was long-pressed. Extra: " - + r.getExtra()); - selectedURL = r.getExtra(); - webvDescription.showContextMenu(); - return true; - } - selectedURL = null; - return false; - } - }; - - @SuppressWarnings("deprecation") - @SuppressLint("NewApi") - @Override - public boolean onContextItemSelected(MenuItem item) { - boolean handled = selectedURL != null; - if (selectedURL != null) { - switch (item.getItemId()) { - case R.id.open_in_browser_item: - Uri uri = Uri.parse(selectedURL); - getActivity() - .startActivity(new Intent(Intent.ACTION_VIEW, uri)); - break; - case R.id.share_url_item: - ShareUtils.shareLink(getActivity(), selectedURL); - break; - case R.id.copy_url_item: - if (android.os.Build.VERSION.SDK_INT >= 11) { - ClipData clipData = ClipData.newPlainText(selectedURL, - selectedURL); - android.content.ClipboardManager cm = (android.content.ClipboardManager) getActivity() - .getSystemService(Context.CLIPBOARD_SERVICE); - cm.setPrimaryClip(clipData); - } else { - android.text.ClipboardManager cm = (android.text.ClipboardManager) getActivity() - .getSystemService(Context.CLIPBOARD_SERVICE); - cm.setText(selectedURL); - } - Toast t = Toast.makeText(getActivity(), - R.string.copied_url_msg, Toast.LENGTH_SHORT); - t.show(); - break; - default: - handled = false; - break; - - } - selectedURL = null; - } - return handled; - - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { - if (selectedURL != null) { - super.onCreateContextMenu(menu, v, menuInfo); - menu.add(Menu.NONE, R.id.open_in_browser_item, Menu.NONE, - R.string.open_in_browser_label); - menu.add(Menu.NONE, R.id.copy_url_item, Menu.NONE, - R.string.copy_url_label); - menu.add(Menu.NONE, R.id.share_url_item, Menu.NONE, - R.string.share_url_label); - menu.setHeaderTitle(selectedURL); - } - } - - private AsyncTask<Void, Void, Void> createLoader() { - return new AsyncTask<Void, Void, Void>() { - @Override - protected void onCancelled() { - super.onCancelled(); - if (getSherlockActivity() != null) { - getSherlockActivity() - .setSupportProgressBarIndeterminateVisibility(false); - } - webViewLoader = null; - } - - String data; - - @Override - protected void onPostExecute(Void result) { - super.onPostExecute(result); - // /webvDescription.loadData(url, "text/html", "utf-8"); - webvDescription.loadDataWithBaseURL(null, data, "text/html", - "utf-8", "about:blank"); - if (getSherlockActivity() != null) { - getSherlockActivity() - .setSupportProgressBarIndeterminateVisibility(false); - } - if (AppConfig.DEBUG) - Log.d(TAG, "Webview loaded"); - webViewLoader = null; - } - - @Override - protected void onPreExecute() { - super.onPreExecute(); - if (getSherlockActivity() != null) { - getSherlockActivity() - .setSupportProgressBarIndeterminateVisibility(true); - } - } - - @Override - protected Void doInBackground(Void... params) { - if (AppConfig.DEBUG) - Log.d(TAG, "Loading Webview"); - data = ""; - data = StringEscapeUtils.unescapeHtml4(shownotes); - Activity activity = getActivity(); - if (activity != null) { - TypedArray res = getActivity() - .getTheme() - .obtainStyledAttributes( - new int[] { android.R.attr.textColorPrimary }); - int colorResource = res.getColor(0, 0); - String colorString = String.format("#%06X", - 0xFFFFFF & colorResource); - Log.i(TAG, "text color: " + colorString); - res.recycle(); - data = applyWebviewStyle(colorString, data); - } else { - cancel(true); - } - return null; - } - - }; - } - - @Override - public void onPause() { - super.onPause(); - savePreference(); - } - - private void savePreference() { - if (saveState) { - if (AppConfig.DEBUG) - Log.d(TAG, "Saving preferences"); - SharedPreferences prefs = getActivity().getSharedPreferences(PREF, - Activity.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - if (media != null && webvDescription != null) { - if (AppConfig.DEBUG) - Log.d(TAG, - "Saving scroll position: " - + webvDescription.getScrollY()); - editor.putInt(PREF_SCROLL_Y, webvDescription.getScrollY()); - editor.putString(PREF_PLAYABLE_ID, media.getIdentifier() - .toString()); - } else { - if (AppConfig.DEBUG) - Log.d(TAG, - "savePreferences was called while media or webview was null"); - editor.putInt(PREF_SCROLL_Y, -1); - editor.putString(PREF_PLAYABLE_ID, ""); - } - editor.commit(); - } - } - - private boolean restoreFromPreference() { - if (saveState) { - if (AppConfig.DEBUG) - Log.d(TAG, "Restoring from preferences"); - Activity activity = getActivity(); - if (activity != null) { - SharedPreferences prefs = activity.getSharedPreferences( - PREF, Activity.MODE_PRIVATE); - String id = prefs.getString(PREF_PLAYABLE_ID, ""); - int scrollY = prefs.getInt(PREF_SCROLL_Y, -1); - if (scrollY != -1 && media != null - && id.equals(media.getIdentifier().toString()) - && webvDescription != null) { - if (AppConfig.DEBUG) - Log.d(TAG, "Restored scroll Position: " + scrollY); - webvDescription.scrollTo(webvDescription.getScrollX(), - scrollY); - return true; - } - } - } - return false; - } + private static final String TAG = "ItemDescriptionFragment"; + + private static final String PREF = "ItemDescriptionFragmentPrefs"; + private static final String PREF_SCROLL_Y = "prefScrollY"; + private static final String PREF_PLAYABLE_ID = "prefPlayableId"; + + private static final String ARG_PLAYABLE = "arg.playable"; + private static final String ARG_FEEDITEM_ID = "arg.feeditem"; + + private static final String ARG_SAVE_STATE = "arg.saveState"; + + private WebView webvDescription; + + private ShownotesProvider shownotesProvider; + private Playable media; + + + private AsyncTask<Void, Void, Void> webViewLoader; + + /** + * URL that was selected via long-press. + */ + private String selectedURL; + + /** + * True if Fragment should save its state (e.g. scrolling position) in a + * shared preference. + */ + private boolean saveState; + + public static ItemDescriptionFragment newInstance(Playable media, + boolean saveState) { + ItemDescriptionFragment f = new ItemDescriptionFragment(); + Bundle args = new Bundle(); + args.putParcelable(ARG_PLAYABLE, media); + args.putBoolean(ARG_SAVE_STATE, saveState); + f.setArguments(args); + return f; + } + + public static ItemDescriptionFragment newInstance(FeedItem item, boolean saveState) { + ItemDescriptionFragment f = new ItemDescriptionFragment(); + Bundle args = new Bundle(); + args.putLong(ARG_FEEDITEM_ID, item.getId()); + args.putBoolean(ARG_SAVE_STATE, saveState); + f.setArguments(args); + return f; + } + + @SuppressLint("NewApi") + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + if (AppConfig.DEBUG) + Log.d(TAG, "Creating view"); + webvDescription = new WebView(getActivity()); + if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) { + if (Build.VERSION.SDK_INT >= 11 + && Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { + webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null); + } + webvDescription.setBackgroundColor(getResources().getColor( + R.color.black)); + } + webvDescription.getSettings().setUseWideViewPort(false); + webvDescription.getSettings().setLayoutAlgorithm( + LayoutAlgorithm.NARROW_COLUMNS); + webvDescription.getSettings().setLoadWithOverviewMode(true); + webvDescription.setOnLongClickListener(webViewLongClickListener); + webvDescription.setWebViewClient(new WebViewClient() { + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + startActivity(intent); + return true; + } + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + if (AppConfig.DEBUG) + Log.d(TAG, "Page finished"); + // Restoring the scroll position might not always work + view.postDelayed(new Runnable() { + + @Override + public void run() { + restoreFromPreference(); + } + + }, 50); + } + + }); + registerForContextMenu(webvDescription); + return webvDescription; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + if (AppConfig.DEBUG) + Log.d(TAG, "Fragment attached"); + } + + @Override + public void onDetach() { + super.onDetach(); + if (AppConfig.DEBUG) + Log.d(TAG, "Fragment detached"); + if (webViewLoader != null) { + webViewLoader.cancel(true); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (AppConfig.DEBUG) + Log.d(TAG, "Fragment destroyed"); + if (webViewLoader != null) { + webViewLoader.cancel(true); + } + } + + @SuppressLint("NewApi") + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (AppConfig.DEBUG) + Log.d(TAG, "Creating fragment"); + Bundle args = getArguments(); + saveState = args.getBoolean(ARG_SAVE_STATE, false); + + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + Bundle args = getArguments(); + if (args.containsKey(ARG_PLAYABLE)) { + media = args.getParcelable(ARG_PLAYABLE); + shownotesProvider = media; + startLoader(); + } else if (args.containsKey(ARG_FEEDITEM_ID)) { + AsyncTask<Void, Void, FeedItem> itemLoadTask = new AsyncTask<Void, Void, FeedItem>() { + + @Override + protected FeedItem doInBackground(Void... voids) { + return DBReader.getFeedItem(getActivity(), getArguments().getLong(ARG_FEEDITEM_ID)); + } + + @Override + protected void onPostExecute(FeedItem feedItem) { + super.onPostExecute(feedItem); + shownotesProvider = feedItem; + startLoader(); + } + }; + if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { + itemLoadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } else { + itemLoadTask.execute(); + } + } + + + } + + @Override + public void onResume() { + super.onResume(); + } + + @SuppressLint("NewApi") + private void startLoader() { + webViewLoader = createLoader(); + if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { + webViewLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } else { + webViewLoader.execute(); + } + } + + /** + * Return the CSS style of the Webview. + * + * @param textColor the default color to use for the text in the webview. This + * value is inserted directly into the CSS String. + */ + private String applyWebviewStyle(String textColor, String data) { + final String WEBVIEW_STYLE = "<html><head><style type=\"text/css\"> * { color: %s; font-family: Helvetica; line-height: 1.5em; font-size: 11pt; } a { font-style: normal; text-decoration: none; font-weight: normal; color: #00A8DF; } img { display: block; margin: 10 auto; max-width: %s; height: auto; } body { margin: %dpx %dpx %dpx %dpx; }</style></head><body>%s</body></html>"; + final int pageMargin = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, 8, getResources() + .getDisplayMetrics()); + return String.format(WEBVIEW_STYLE, textColor, "100%", pageMargin, + pageMargin, pageMargin, pageMargin, data); + } + + private View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() { + + @Override + public boolean onLongClick(View v) { + WebView.HitTestResult r = webvDescription.getHitTestResult(); + if (r != null + && r.getType() == WebView.HitTestResult.SRC_ANCHOR_TYPE) { + if (AppConfig.DEBUG) + Log.d(TAG, + "Link of webview was long-pressed. Extra: " + + r.getExtra()); + selectedURL = r.getExtra(); + webvDescription.showContextMenu(); + return true; + } + selectedURL = null; + return false; + } + }; + + @SuppressWarnings("deprecation") + @SuppressLint("NewApi") + @Override + public boolean onContextItemSelected(MenuItem item) { + boolean handled = selectedURL != null; + if (selectedURL != null) { + switch (item.getItemId()) { + case R.id.open_in_browser_item: + Uri uri = Uri.parse(selectedURL); + getActivity() + .startActivity(new Intent(Intent.ACTION_VIEW, uri)); + break; + case R.id.share_url_item: + ShareUtils.shareLink(getActivity(), selectedURL); + break; + case R.id.copy_url_item: + if (android.os.Build.VERSION.SDK_INT >= 11) { + ClipData clipData = ClipData.newPlainText(selectedURL, + selectedURL); + android.content.ClipboardManager cm = (android.content.ClipboardManager) getActivity() + .getSystemService(Context.CLIPBOARD_SERVICE); + cm.setPrimaryClip(clipData); + } else { + android.text.ClipboardManager cm = (android.text.ClipboardManager) getActivity() + .getSystemService(Context.CLIPBOARD_SERVICE); + cm.setText(selectedURL); + } + Toast t = Toast.makeText(getActivity(), + R.string.copied_url_msg, Toast.LENGTH_SHORT); + t.show(); + break; + default: + handled = false; + break; + + } + selectedURL = null; + } + return handled; + + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + if (selectedURL != null) { + super.onCreateContextMenu(menu, v, menuInfo); + menu.add(Menu.NONE, R.id.open_in_browser_item, Menu.NONE, + R.string.open_in_browser_label); + menu.add(Menu.NONE, R.id.copy_url_item, Menu.NONE, + R.string.copy_url_label); + menu.add(Menu.NONE, R.id.share_url_item, Menu.NONE, + R.string.share_url_label); + menu.setHeaderTitle(selectedURL); + } + } + + private AsyncTask<Void, Void, Void> createLoader() { + return new AsyncTask<Void, Void, Void>() { + @Override + protected void onCancelled() { + super.onCancelled(); + if (getSherlockActivity() != null) { + getSherlockActivity() + .setSupportProgressBarIndeterminateVisibility(false); + } + webViewLoader = null; + } + + String data; + + @Override + protected void onPostExecute(Void result) { + super.onPostExecute(result); + // /webvDescription.loadData(url, "text/html", "utf-8"); + webvDescription.loadDataWithBaseURL(null, data, "text/html", + "utf-8", "about:blank"); + if (getSherlockActivity() != null) { + getSherlockActivity() + .setSupportProgressBarIndeterminateVisibility(false); + } + if (AppConfig.DEBUG) + Log.d(TAG, "Webview loaded"); + webViewLoader = null; + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + if (getSherlockActivity() != null) { + getSherlockActivity() + .setSupportProgressBarIndeterminateVisibility(true); + } + } + + @Override + protected Void doInBackground(Void... params) { + if (AppConfig.DEBUG) + Log.d(TAG, "Loading Webview"); + try { + Callable<String> shownotesLoadTask = shownotesProvider.loadShownotes(); + final String shownotes = shownotesLoadTask.call(); + + data = ""; + data = StringEscapeUtils.unescapeHtml4(shownotes); + Activity activity = getActivity(); + if (activity != null) { + TypedArray res = getActivity() + .getTheme() + .obtainStyledAttributes( + new int[]{android.R.attr.textColorPrimary}); + int colorResource = res.getColor(0, 0); + String colorString = String.format("#%06X", + 0xFFFFFF & colorResource); + Log.i(TAG, "text color: " + colorString); + res.recycle(); + data = applyWebviewStyle(colorString, data); + } else { + cancel(true); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + }; + } + + @Override + public void onPause() { + super.onPause(); + savePreference(); + } + + private void savePreference() { + if (saveState) { + if (AppConfig.DEBUG) + Log.d(TAG, "Saving preferences"); + SharedPreferences prefs = getActivity().getSharedPreferences(PREF, + Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + if (media != null && webvDescription != null) { + if (AppConfig.DEBUG) + Log.d(TAG, + "Saving scroll position: " + + webvDescription.getScrollY()); + editor.putInt(PREF_SCROLL_Y, webvDescription.getScrollY()); + editor.putString(PREF_PLAYABLE_ID, media.getIdentifier() + .toString()); + } else { + if (AppConfig.DEBUG) + Log.d(TAG, + "savePreferences was called while media or webview was null"); + editor.putInt(PREF_SCROLL_Y, -1); + editor.putString(PREF_PLAYABLE_ID, ""); + } + editor.commit(); + } + } + + private boolean restoreFromPreference() { + if (saveState) { + if (AppConfig.DEBUG) + Log.d(TAG, "Restoring from preferences"); + Activity activity = getActivity(); + if (activity != null) { + SharedPreferences prefs = activity.getSharedPreferences( + PREF, Activity.MODE_PRIVATE); + String id = prefs.getString(PREF_PLAYABLE_ID, ""); + int scrollY = prefs.getInt(PREF_SCROLL_Y, -1); + if (scrollY != -1 && media != null + && id.equals(media.getIdentifier().toString()) + && webvDescription != null) { + if (AppConfig.DEBUG) + Log.d(TAG, "Restored scroll Position: " + scrollY); + webvDescription.scrollTo(webvDescription.getScrollX(), + scrollY); + return true; + } + } + } + return false; + } } diff --git a/src/de/danoeh/antennapod/storage/DBReader.java b/src/de/danoeh/antennapod/storage/DBReader.java index c69607473..bf81ad7d4 100644 --- a/src/de/danoeh/antennapod/storage/DBReader.java +++ b/src/de/danoeh/antennapod/storage/DBReader.java @@ -476,6 +476,21 @@ public final class DBReader { return item; } + + public static void loadExtraInformationOfFeedItem(final Context context, final FeedItem item) { + PodDBAdapter adapter = new PodDBAdapter(context); + adapter.open(); + Cursor extraCursor = adapter.getExtraInformationOfItem(item); + if (extraCursor.moveToFirst()) { + String description = extraCursor + .getString(PodDBAdapter.IDX_FI_EXTRA_DESCRIPTION); + String contentEncoded = extraCursor + .getString(PodDBAdapter.IDX_FI_EXTRA_CONTENT_ENCODED); + item.setDescription(description); + item.setContentEncoded(contentEncoded); + } + adapter.close(); + } public static int getNumberOfDownloadedEpisodes(final Context context) { PodDBAdapter adapter = new PodDBAdapter(context); diff --git a/src/de/danoeh/antennapod/storage/DBWriter.java b/src/de/danoeh/antennapod/storage/DBWriter.java index a60694f35..3db0b8a33 100644 --- a/src/de/danoeh/antennapod/storage/DBWriter.java +++ b/src/de/danoeh/antennapod/storage/DBWriter.java @@ -529,10 +529,20 @@ public class DBWriter { adapter.setMedia(media); adapter.close(); }}); - - } + public static Future<?> setFeedMediaPosition(final Context context, final FeedMedia media) { + return dbExec.submit(new Runnable(){ + @Override + public void run() { + PodDBAdapter adapter = new PodDBAdapter(context); + adapter.open(); + adapter.setFeedMediaPosition(media); + adapter.close(); + } + }); + } + public static Future<?> setFeedItem(final Context context, final FeedItem item) { return dbExec.submit(new Runnable() { diff --git a/src/de/danoeh/antennapod/storage/PodDBAdapter.java b/src/de/danoeh/antennapod/storage/PodDBAdapter.java index 14ef07c34..4ef76fcd6 100644 --- a/src/de/danoeh/antennapod/storage/PodDBAdapter.java +++ b/src/de/danoeh/antennapod/storage/PodDBAdapter.java @@ -366,6 +366,17 @@ public class PodDBAdapter { return media.getId(); } + public void setFeedMediaPosition(FeedMedia media) { + if (media.getId() != 0) { + ContentValues values = new ContentValues(); + values.put(KEY_POSITION, media.getPosition()); + db.update(TABLE_NAME_FEED_MEDIA, values, KEY_ID + "=?", + new String[] { String.valueOf(media.getId()) }); + } else { + Log.e(TAG, "setFeedMediaPosition: ID of media was 0"); + } + } + /** * Insert all FeedItems of a feed and the feed object itself in a single * transaction diff --git a/src/de/danoeh/antennapod/util/playback/ExternalMedia.java b/src/de/danoeh/antennapod/util/playback/ExternalMedia.java index c0a92904b..1ada0ec03 100644 --- a/src/de/danoeh/antennapod/util/playback/ExternalMedia.java +++ b/src/de/danoeh/antennapod/util/playback/ExternalMedia.java @@ -2,6 +2,7 @@ package de.danoeh.antennapod.util.playback; import java.io.InputStream; import java.util.List; +import java.util.concurrent.Callable; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; @@ -95,8 +96,13 @@ public class ExternalMedia implements Playable { } @Override - public void loadShownotes(ShownoteLoaderCallback callback) { - callback.onShownotesLoaded(null); + public Callable<String> loadShownotes() { + return new Callable<String>() { + @Override + public String call() throws Exception { + return ""; + } + }; } @Override diff --git a/src/de/danoeh/antennapod/util/playback/Playable.java b/src/de/danoeh/antennapod/util/playback/Playable.java index 39c6c6b83..98d5fbb36 100644 --- a/src/de/danoeh/antennapod/util/playback/Playable.java +++ b/src/de/danoeh/antennapod/util/playback/Playable.java @@ -3,9 +3,11 @@ package de.danoeh.antennapod.util.playback; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.List; +import java.util.concurrent.FutureTask; import android.content.Context; import de.danoeh.antennapod.storage.DBReader; +import de.danoeh.antennapod.util.ShownotesProvider; import org.apache.commons.io.IOUtils; import android.content.SharedPreferences; @@ -14,7 +16,6 @@ import android.os.Parcelable; import android.util.Log; import de.danoeh.antennapod.asynctask.ImageLoader; import de.danoeh.antennapod.feed.Chapter; -import de.danoeh.antennapod.feed.Feed; import de.danoeh.antennapod.feed.FeedMedia; import de.danoeh.antennapod.feed.MediaType; @@ -22,7 +23,7 @@ import de.danoeh.antennapod.feed.MediaType; * Interface for objects that can be played by the PlaybackService. */ public interface Playable extends Parcelable, - ImageLoader.ImageWorkerTaskResource { + ImageLoader.ImageWorkerTaskResource, ShownotesProvider { /** * Save information about the playable in a preference so that it can be @@ -53,13 +54,6 @@ public interface Playable extends Parcelable, public String getEpisodeTitle(); /** - * Loads shownotes. If the shownotes have to be loaded from a file or from a - * database, it should be done in a separate thread. After the shownotes - * have been loaded, callback.onShownotesLoaded should be called. - */ - public void loadShownotes(ShownoteLoaderCallback callback); - - /** * Returns a list of chapter marks or null if this Playable has no chapters. */ public List<Chapter> getChapters(); @@ -216,10 +210,6 @@ public interface Playable extends Parcelable, } - public static interface ShownoteLoaderCallback { - void onShownotesLoaded(String shownotes); - } - /** * Uses local file as image resource if it is available. */ |