diff options
-rw-r--r-- | src/de/danoeh/antennapod/activity/SearchActivity.java | 78 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/feed/Feed.java | 9 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/feed/FeedItem.java | 67 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/feed/FeedManager.java | 188 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/feed/FeedSearcher.java | 157 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java | 39 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/storage/PodDBAdapter.java | 100 |
7 files changed, 496 insertions, 142 deletions
diff --git a/src/de/danoeh/antennapod/activity/SearchActivity.java b/src/de/danoeh/antennapod/activity/SearchActivity.java index a073b43cc..9b2f5188b 100644 --- a/src/de/danoeh/antennapod/activity/SearchActivity.java +++ b/src/de/danoeh/antennapod/activity/SearchActivity.java @@ -69,8 +69,10 @@ public class SearchActivity extends SherlockListActivity { if (AppConfig.DEBUG) Log.d(TAG, "Starting search"); String query = intent.getStringExtra(SearchManager.QUERY); - getSupportActionBar().setSubtitle( - getString(R.string.search_term_label) + "\"" + query + "\""); + getSupportActionBar() + .setSubtitle( + getString(R.string.search_term_label) + "\"" + + query + "\""); handleSearchRequest(query); } } @@ -133,48 +135,46 @@ public class SearchActivity extends SherlockListActivity { } @SuppressLint({ "NewApi", "NewApi" }) - private void handleSearchRequest(String query) { - AsyncTask<String, Void, ArrayList<SearchResult>> executor = new AsyncTask<String, Void, ArrayList<SearchResult>>() { - - @Override - protected void onPreExecute() { - if (searchAdapter != null) { - searchAdapter.clear(); - searchAdapter.notifyDataSetChanged(); - } - txtvStatus.setText(R.string.search_status_searching); - } + private void handleSearchRequest(final String query) { + if (searchAdapter != null) { + searchAdapter.clear(); + searchAdapter.notifyDataSetChanged(); + } + txtvStatus.setText(R.string.search_status_searching); - @Override - protected ArrayList<SearchResult> doInBackground(String... params) { - if (AppConfig.DEBUG) - Log.d(TAG, "Starting background work"); - return FeedSearcher.performSearch(params[0], selectedFeed); - } + Thread thread = new Thread() { @Override - protected void onPostExecute(ArrayList<SearchResult> result) { - if (AppConfig.DEBUG) - Log.d(TAG, "Background work finished"); - if (AppConfig.DEBUG) - Log.d(TAG, "Found " + result.size() + " results"); - content = result; - - searchAdapter = new SearchlistAdapter(SearchActivity.this, 0, - content); - getListView().setAdapter(searchAdapter); - searchAdapter.notifyDataSetChanged(); - if (content.isEmpty()) { - txtvStatus.setText(R.string.search_status_no_results); + public void run() { + Log.d(TAG, "Starting background work"); + final ArrayList<SearchResult> result = FeedSearcher + .performSearch(SearchActivity.this, query, selectedFeed); + if (SearchActivity.this != null) { + SearchActivity.this.runOnUiThread(new Runnable() { + + @Override + public void run() { + if (AppConfig.DEBUG) + Log.d(TAG, "Background work finished"); + if (AppConfig.DEBUG) + Log.d(TAG, "Found " + result.size() + + " results"); + content = result; + + searchAdapter = new SearchlistAdapter( + SearchActivity.this, 0, content); + getListView().setAdapter(searchAdapter); + searchAdapter.notifyDataSetChanged(); + if (content.isEmpty()) { + txtvStatus + .setText(R.string.search_status_no_results); + } + } + }); } - } - }; - if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { - executor.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, query); - } else { - executor.execute(query); - } + thread.start(); + } } diff --git a/src/de/danoeh/antennapod/feed/Feed.java b/src/de/danoeh/antennapod/feed/Feed.java index 6cea571f6..55256ea31 100644 --- a/src/de/danoeh/antennapod/feed/Feed.java +++ b/src/de/danoeh/antennapod/feed/Feed.java @@ -144,6 +144,15 @@ public class Feed extends FeedFile { return download_url; } } + + /** Calls cacheDescriptions on all items. */ + protected void cacheDescriptionsOfItems() { + if (items != null) { + for (FeedItem item : items) { + item.cacheDescriptions(); + } + } + } @Override public int getTypeAsInt() { diff --git a/src/de/danoeh/antennapod/feed/FeedItem.java b/src/de/danoeh/antennapod/feed/FeedItem.java index 93655f8cb..6227298df 100644 --- a/src/de/danoeh/antennapod/feed/FeedItem.java +++ b/src/de/danoeh/antennapod/feed/FeedItem.java @@ -1,5 +1,6 @@ package de.danoeh.antennapod.feed; +import java.lang.ref.SoftReference; import java.util.Date; import java.util.List; @@ -13,11 +14,23 @@ import de.danoeh.antennapod.PodcastApp; */ public class FeedItem extends FeedComponent { - /** The id/guid that can be found in the rss/atom feed. Might not be set.*/ + /** 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; @@ -30,16 +43,19 @@ public class FeedItem extends FeedComponent { this.read = true; } - public FeedItem(String title, String description, String link, - Date pubDate, FeedMedia media, Feed feed) { - super(); - this.title = title; - this.description = description; - this.link = link; - this.pubDate = pubDate; - this.media = media; - this.feed = feed; - this.read = true; + /** + * 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; } /** Get the chapter that fits the position. */ @@ -62,11 +78,12 @@ public class FeedItem extends FeedComponent { public Chapter getCurrentChapter() { return getCurrentChapter(media.getPosition()); } - - /** 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. + + /** + * 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) { @@ -87,6 +104,9 @@ public class FeedItem extends FeedComponent { } public String getDescription() { + if (description == null && cachedDescription != null) { + return cachedDescription.get(); + } return description; } @@ -131,6 +151,10 @@ public class FeedItem extends FeedComponent { } public String getContentEncoded() { + if (contentEncoded == null && cachedContentEncoded != null) { + return cachedContentEncoded.get(); + + } return contentEncoded; } @@ -161,7 +185,7 @@ public class FeedItem extends FeedComponent { public void setItemIdentifier(String itemIdentifier) { this.itemIdentifier = itemIdentifier; } - + public boolean isPlaying() { if (media != null) { if (PodcastApp.getCurrentlyPlayingMediaId() == media.getId()) { @@ -170,6 +194,13 @@ public class FeedItem extends FeedComponent { } return false; } - + + public void setCachedDescription(String d) { + cachedDescription = new SoftReference<String>(d); + } + + public void setCachedContentEncoded(String c) { + cachedContentEncoded = new SoftReference<String>(c); + } } diff --git a/src/de/danoeh/antennapod/feed/FeedManager.java b/src/de/danoeh/antennapod/feed/FeedManager.java index 3f774b4bd..7f4a1c5aa 100644 --- a/src/de/danoeh/antennapod/feed/FeedManager.java +++ b/src/de/danoeh/antennapod/feed/FeedManager.java @@ -774,6 +774,7 @@ public class FeedManager { PodDBAdapter adapter = new PodDBAdapter(context); adapter.open(); adapter.setCompleteFeed(feed); + feed.cacheDescriptionsOfItems(); adapter.close(); } }); @@ -867,6 +868,7 @@ public class FeedManager { public void setFeed(Feed feed, PodDBAdapter adapter) { if (adapter != null) { adapter.setFeed(feed); + feed.cacheDescriptionsOfItems(); } else { Log.w(TAG, "Adapter in setFeed was null"); } @@ -914,6 +916,7 @@ public class FeedManager { PodDBAdapter adapter = new PodDBAdapter(context); adapter.open(); adapter.setFeed(feed); + feed.cacheDescriptionsOfItems(); adapter.close(); } }); @@ -1009,6 +1012,19 @@ public class FeedManager { return null; } + /** Get a FeedItem by its id and the id of its feed. */ + public FeedItem getFeedItem(long itemId, long feedId) { + Feed feed = getFeed(feedId); + if (feed != null && feed.getItems() != null) { + for (FeedItem item : feed.getItems()) { + if (item.getId() == itemId) { + return item; + } + } + } + return null; + } + /** Get a FeedMedia object by the id of the Media object and the feed object */ public FeedMedia getFeedMedia(long id, Feed feed) { if (feed != null) { @@ -1129,37 +1145,34 @@ public class FeedManager { do { FeedItem item = new FeedItem(); - item.id = itemlistCursor.getLong(PodDBAdapter.KEY_ID_INDEX); + item.id = itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_ID); item.setFeed(feed); item.setTitle(itemlistCursor - .getString(PodDBAdapter.KEY_TITLE_INDEX)); + .getString(PodDBAdapter.IDX_FI_SMALL_TITLE)); item.setLink(itemlistCursor - .getString(PodDBAdapter.KEY_LINK_INDEX)); - item.setDescription(itemlistCursor - .getString(PodDBAdapter.KEY_DESCRIPTION_INDEX)); - item.setContentEncoded(itemlistCursor - .getString(PodDBAdapter.KEY_CONTENT_ENCODED_INDEX)); + .getString(PodDBAdapter.IDX_FI_SMALL_LINK)); item.setPubDate(new Date(itemlistCursor - .getLong(PodDBAdapter.KEY_PUBDATE_INDEX))); + .getLong(PodDBAdapter.IDX_FI_SMALL_PUBDATE))); item.setPaymentLink(itemlistCursor - .getString(PodDBAdapter.KEY_PAYMENT_LINK_INDEX)); + .getString(PodDBAdapter.IDX_FI_SMALL_PAYMENT_LINK)); long mediaId = itemlistCursor - .getLong(PodDBAdapter.KEY_MEDIA_INDEX); + .getLong(PodDBAdapter.IDX_FI_SMALL_MEDIA); if (mediaId != 0) { mediaIds.add(String.valueOf(mediaId)); item.setMedia(new FeedMedia(mediaId, item)); } - item.read = (itemlistCursor.getInt(PodDBAdapter.KEY_READ_INDEX) > 0) ? true + item.read = (itemlistCursor + .getInt(PodDBAdapter.IDX_FI_SMALL_READ) > 0) ? true : false; item.setItemIdentifier(itemlistCursor - .getString(PodDBAdapter.KEY_ITEM_IDENTIFIER_INDEX)); + .getString(PodDBAdapter.IDX_FI_SMALL_ITEM_IDENTIFIER)); if (!item.read) { unreadItems.add(item); } // extract chapters boolean hasSimpleChapters = itemlistCursor - .getInt(PodDBAdapter.KEY_HAS_SIMPLECHAPTERS_INDEX) > 0; + .getInt(PodDBAdapter.IDX_FI_SMALL_HAS_CHAPTERS) > 0; if (hasSimpleChapters) { Cursor chapterCursor = adapter .getSimpleChaptersOfFeedItemCursor(item); @@ -1325,6 +1338,57 @@ public class FeedManager { cursor.close(); } + public void loadExtraInformationOfItem(final Context context, + final FeedItem item, FeedManager.TaskCallback callback) { + if (AppConfig.DEBUG) + Log.d(TAG, + "Loading extra information of item with id " + item.getId()); + dbExec.execute(new FeedManager.Task(new Handler(), callback) { + + @Override + public void execute() { + PodDBAdapter adapter = new PodDBAdapter(context); + adapter.open(); + Cursor extraCursor = adapter.getExtraInformationOfItem(item); + if (extraCursor.moveToFirst()) { + item.setCachedDescription(extraCursor + .getString(PodDBAdapter.IDX_FI_EXTRA_DESCRIPTION)); + item.setCachedContentEncoded(extraCursor + .getString(PodDBAdapter.IDX_FI_EXTRA_CONTENT_ENCODED)); + } + adapter.close(); + } + }); + } + + public void searchFeedItemDescription(final Context context, + final Feed feed, final String query, + FeedManager.QueryTaskCallback callback) { + dbExec.execute(new FeedManager.QueryTask(context, new Handler(), callback) { + + @Override + public void execute(PodDBAdapter adapter) { + Cursor searchResult = adapter.searchItemDescriptions(feed, + query); + setResult(searchResult); + } + }); + } + + public void searchFeedItemContentEncoded(final Context context, + final Feed feed, final String query, + FeedManager.QueryTaskCallback callback) { + dbExec.execute(new FeedManager.QueryTask(context, new Handler(), callback) { + + @Override + public void execute(PodDBAdapter adapter) { + Cursor searchResult = adapter.searchItemContentEncoded(feed, + query); + setResult(searchResult); + } + }); + } + public List<Feed> getFeeds() { return feeds; } @@ -1345,4 +1409,102 @@ public class FeedManager { return playbackHistory; } + /** Is called by a FeedManagerTask after completion. */ + public interface TaskCallback { + void onCompletion(Cursor result); + } + + /** Is called by a FeedManager.QueryTask after completion. */ + public interface QueryTaskCallback { + void handleResult(Cursor result); + void onCompletion(); + } + + /** A runnable that can post a callback to a handler after completion. */ + abstract class Task implements Runnable { + private Handler handler; + private TaskCallback callback; + + /** + * Standard contructor. No callbacks are going to be posted to a + * handler. + */ + public Task() { + super(); + } + + /** + * The Task will post a Runnable to 'handler' that will execute the + * 'callback' after completion. + */ + public Task(Handler handler, TaskCallback callback) { + super(); + this.handler = handler; + this.callback = callback; + } + + @Override + public final void run() { + execute(); + if (handler != null && callback != null) { + handler.post(new Runnable() { + @Override + public void run() { + callback.onCompletion(null); + } + }); + } + } + + /** This method will be executed in the same thread as the run() method. */ + public abstract void execute(); + } + + /** + * A runnable which should be used for database queries. The onCompletion + * method is executed on the database executor to handle Cursors correctly. + * This class automatically creates a PodDBAdapter object and closes it when + * it is no longer in use. + */ + abstract class QueryTask implements Runnable { + private QueryTaskCallback callback; + private Cursor result; + private Context context; + private Handler handler; + + public QueryTask(Context context, Handler handler, QueryTaskCallback callback) { + this.callback = callback; + this.context = context; + this.handler = handler; + } + + @Override + public final void run() { + PodDBAdapter adapter = new PodDBAdapter(context); + adapter.open(); + execute(adapter); + callback.handleResult(result); + if (result != null && !result.isClosed()) { + result.close(); + } + adapter.close(); + if (handler != null && callback != null) { + handler.post(new Runnable() { + + @Override + public void run() { + callback.onCompletion(); + } + + }); + } + } + + public abstract void execute(PodDBAdapter adapter); + + protected void setResult(Cursor c) { + result = c; + } + } + } diff --git a/src/de/danoeh/antennapod/feed/FeedSearcher.java b/src/de/danoeh/antennapod/feed/FeedSearcher.java index f53ff5ae7..ab7c174bc 100644 --- a/src/de/danoeh/antennapod/feed/FeedSearcher.java +++ b/src/de/danoeh/antennapod/feed/FeedSearcher.java @@ -5,10 +5,14 @@ import java.util.Collections; import java.util.regex.Matcher; import java.util.regex.Pattern; +import android.content.Context; +import android.database.Cursor; +import android.os.Looper; import android.util.Log; import de.danoeh.antennapod.AppConfig; import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.storage.PodDBAdapter; import de.danoeh.antennapod.util.comparator.SearchResultValueComparator; /** Performs search on Feeds and FeedItems */ @@ -23,10 +27,10 @@ public class FeedSearcher { private static final int VALUE_WORD_MATCH = 4; /** Performs a search in all feeds or one specific feed. */ - public static ArrayList<SearchResult> performSearch(final String query, - Feed selectedFeed) { - String lcQuery = query.toLowerCase(); - ArrayList<SearchResult> result = new ArrayList<SearchResult>(); + public static ArrayList<SearchResult> performSearch(final Context context, + final String query, final Feed selectedFeed) { + final String lcQuery = query.toLowerCase(); + final ArrayList<SearchResult> result = new ArrayList<SearchResult>(); if (selectedFeed == null) { if (AppConfig.DEBUG) Log.d(TAG, "Performing global search"); @@ -45,14 +49,40 @@ public class FeedSearcher { Log.d(TAG, "Searching item-chaptertitles"); searchFeedItemChapters(lcQuery, result, selectedFeed); - if (AppConfig.DEBUG) - Log.d(TAG, "Searching item descriptions"); - searchFeedItemDescription(lcQuery, result, selectedFeed); + final FeedManager manager = FeedManager.getInstance(); + Looper.prepare(); + manager.searchFeedItemDescription(context, selectedFeed, lcQuery, + new FeedManager.QueryTaskCallback() { - if (AppConfig.DEBUG) - Log.d(TAG, "Searching item content encoded data"); - searchFeedItemContentEncoded(lcQuery, result, selectedFeed); + @Override + public void handleResult(Cursor cResult) { + searchFeedItemContentEncodedCursor(lcQuery, result, + selectedFeed, cResult); + + } + @Override + public void onCompletion() { + manager.searchFeedItemContentEncoded(context, + selectedFeed, lcQuery, + new FeedManager.QueryTaskCallback() { + + @Override + public void handleResult(Cursor cResult) { + searchFeedItemDescriptionCursor( + lcQuery, result, selectedFeed, + cResult); + } + + @Override + public void onCompletion() { + Looper.myLooper().quit(); + } + }); + } + }); + + Looper.loop(); if (AppConfig.DEBUG) Log.d(TAG, "Sorting results"); Collections.sort(result, new SearchResultValueComparator()); @@ -127,61 +157,74 @@ public class FeedSearcher { } } - private static void searchFeedItemDescription(String query, - ArrayList<SearchResult> destination, Feed selectedFeed) { + private static void searchFeedItemDescriptionCursor(String query, + ArrayList<SearchResult> destination, Feed feed, Cursor cursor) { FeedManager manager = FeedManager.getInstance(); - if (selectedFeed == null) { - for (Feed feed : manager.getFeeds()) { - searchFeedItemDescriptionSingleFeed(query, destination, feed); - } - } else { - searchFeedItemDescriptionSingleFeed(query, destination, - selectedFeed); - } - } - - private static void searchFeedItemDescriptionSingleFeed(String query, - ArrayList<SearchResult> destination, Feed feed) { - for (FeedItem item : feed.getItems()) { - if (item.getDescription() != null) { - SearchResult result = createSearchResult(item, query, item - .getDescription().toLowerCase(), VALUE_ITEM_DESCRIPTION); - if (result != null) { - result.setSubtitle(PodcastApp.getInstance().getString( - R.string.found_in_shownotes_label)); - destination.add(result); + if (cursor.moveToFirst()) { + do { + final long itemId = cursor + .getLong(PodDBAdapter.IDX_FI_EXTRA_ID); + String content = cursor + .getString(PodDBAdapter.IDX_FI_EXTRA_DESCRIPTION); + if (content != null) { + content = content.toLowerCase(); + final long feedId = cursor + .getLong(PodDBAdapter.IDX_FI_EXTRA_FEED); + FeedItem item = null; + if (feed == null) { + item = manager.getFeedItem(itemId, feedId); + } else { + item = manager.getFeedItem(itemId, feed); + } + if (item != null) { + SearchResult searchResult = createSearchResult(item, + query, content, VALUE_ITEM_DESCRIPTION); + if (searchResult != null) { + searchResult.setSubtitle(PodcastApp.getInstance() + .getString( + R.string.found_in_shownotes_label)); + destination.add(searchResult); + + } + } } - } + } while (cursor.moveToNext()); } } - private static void searchFeedItemContentEncoded(String query, - ArrayList<SearchResult> destination, Feed selectedFeed) { + private static void searchFeedItemContentEncodedCursor(String query, + ArrayList<SearchResult> destination, Feed feed, Cursor cursor) { FeedManager manager = FeedManager.getInstance(); - if (selectedFeed == null) { - for (Feed feed : manager.getFeeds()) { - searchFeedItemContentEncodedSingleFeed(query, destination, feed); - } - } else { - searchFeedItemContentEncodedSingleFeed(query, destination, - selectedFeed); - } - } - - private static void searchFeedItemContentEncodedSingleFeed(String query, - ArrayList<SearchResult> destination, Feed feed) { - for (FeedItem item : feed.getItems()) { - if (!destination.contains(item) && item.getContentEncoded() != null) { - SearchResult result = createSearchResult(item, query, item - .getContentEncoded().toLowerCase(), - VALUE_ITEM_DESCRIPTION); - if (result != null) { - result.setSubtitle(PodcastApp.getInstance().getString( - R.string.found_in_shownotes_label)); - destination.add(result); + if (cursor.moveToFirst()) { + do { + final long itemId = cursor + .getLong(PodDBAdapter.IDX_FI_EXTRA_ID); + String content = cursor + .getString(PodDBAdapter.IDX_FI_EXTRA_CONTENT_ENCODED); + if (content != null) { + content = content.toLowerCase(); + + final long feedId = cursor + .getLong(PodDBAdapter.IDX_FI_EXTRA_FEED); + FeedItem item = null; + if (feed == null) { + item = manager.getFeedItem(itemId, feedId); + } else { + item = manager.getFeedItem(itemId, feed); + } + if (item != null) { + SearchResult searchResult = createSearchResult(item, + query, content, VALUE_ITEM_DESCRIPTION); + if (searchResult != null) { + searchResult.setSubtitle(PodcastApp.getInstance() + .getString( + R.string.found_in_shownotes_label)); + destination.add(searchResult); + } + } } - } + } while (cursor.moveToNext()); } } diff --git a/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java index b05df96b2..42041ce2e 100644 --- a/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java +++ b/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java @@ -4,6 +4,7 @@ import org.apache.commons.lang3.StringEscapeUtils; import android.annotation.SuppressLint; import android.app.Activity; +import android.database.Cursor; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; @@ -104,16 +105,22 @@ public class ItemDescriptionFragment extends SherlockFragment { } } - @SuppressLint("NewApi") @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); if (item != null) { - webViewLoader = createLoader(); - if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { - webViewLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + if (item.getDescription() == null && item.getDescription() == null) { + Log.i(TAG, "Loading data"); + FeedManager.getInstance().loadExtraInformationOfItem( + getActivity(), item, new FeedManager.TaskCallback() { + @Override + public void onCompletion(Cursor result) { + startLoader(); + } + }); } else { - webViewLoader.execute(); + Log.i(TAG, "Using cached data"); + startLoader(); } } else { Log.e(TAG, "Error in onViewCreated: Item was null"); @@ -125,6 +132,16 @@ public class ItemDescriptionFragment extends SherlockFragment { 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(); + } + } + private AsyncTask<Void, Void, Void> createLoader() { return new AsyncTask<Void, Void, Void>() { @Override @@ -145,8 +162,10 @@ public class ItemDescriptionFragment extends SherlockFragment { // /webvDescription.loadData(url, "text/html", "utf-8"); webvDescription.loadDataWithBaseURL(null, data, "text/html", "utf-8", "about:blank"); - getSherlockActivity() - .setSupportProgressBarIndeterminateVisibility(false); + if (getSherlockActivity() != null) { + getSherlockActivity() + .setSupportProgressBarIndeterminateVisibility(false); + } if (AppConfig.DEBUG) Log.d(TAG, "Webview loaded"); webViewLoader = null; @@ -155,8 +174,10 @@ public class ItemDescriptionFragment extends SherlockFragment { @Override protected void onPreExecute() { super.onPreExecute(); - getSherlockActivity() - .setSupportProgressBarIndeterminateVisibility(true); + if (getSherlockActivity() != null) { + getSherlockActivity() + .setSupportProgressBarIndeterminateVisibility(true); + } } @Override diff --git a/src/de/danoeh/antennapod/storage/PodDBAdapter.java b/src/de/danoeh/antennapod/storage/PodDBAdapter.java index 5bb0afd2f..9b60521cf 100644 --- a/src/de/danoeh/antennapod/storage/PodDBAdapter.java +++ b/src/de/danoeh/antennapod/storage/PodDBAdapter.java @@ -180,6 +180,39 @@ public class PodDBAdapter { private final Context context; private PodDBHelper helper; + /** + * Select all columns from the feeditems-table except description and + * content-encoded. + */ + private static final String[] SEL_FI_SMALL = { KEY_ID, KEY_TITLE, + KEY_PUBDATE, KEY_READ, KEY_LINK, KEY_PAYMENT_LINK, KEY_MEDIA, + KEY_FEED, KEY_HAS_CHAPTERS, KEY_ITEM_IDENTIFIER }; + + // column indices for SEL_FI_SMALL + + public static final int IDX_FI_SMALL_ID = 0; + public static final int IDX_FI_SMALL_TITLE = 1; + public static final int IDX_FI_SMALL_PUBDATE = 2; + public static final int IDX_FI_SMALL_READ = 3; + public static final int IDX_FI_SMALL_LINK = 4; + public static final int IDX_FI_SMALL_PAYMENT_LINK = 5; + public static final int IDX_FI_SMALL_MEDIA = 6; + public static final int IDX_FI_SMALL_FEED = 7; + public static final int IDX_FI_SMALL_HAS_CHAPTERS = 8; + public static final int IDX_FI_SMALL_ITEM_IDENTIFIER = 9; + + /** Select id, description and content-encoded column from feeditems. */ + public static final String[] SEL_FI_EXTRA = { KEY_ID, KEY_DESCRIPTION, + KEY_CONTENT_ENCODED, KEY_FEED }; + + // column indices for SEL_FI_EXTRA + + public static final int IDX_FI_EXTRA_ID = 0; + public static final int IDX_FI_EXTRA_DESCRIPTION = 1; + public static final int IDX_FI_EXTRA_CONTENT_ENCODED = 2; + public static final int IDX_FI_EXTRA_FEED = 3; + + public PodDBAdapter(Context c) { this.context = c; helper = new PodDBHelper(context, DATABASE_NAME, null, DATABASE_VERSION); @@ -280,7 +313,8 @@ public class PodDBAdapter { values.put(KEY_DOWNLOADED, media.isDownloaded()); values.put(KEY_FILE_URL, media.getFile_url()); if (media.getPlaybackCompletionDate() != null) { - values.put(KEY_PLAYBACK_COMPLETION_DATE, media.getPlaybackCompletionDate().getTime()); + values.put(KEY_PLAYBACK_COMPLETION_DATE, media + .getPlaybackCompletionDate().getTime()); } else { values.put(KEY_PLAYBACK_COMPLETION_DATE, 0); } @@ -324,8 +358,12 @@ public class PodDBAdapter { ContentValues values = new ContentValues(); values.put(KEY_TITLE, item.getTitle()); values.put(KEY_LINK, item.getLink()); - values.put(KEY_DESCRIPTION, item.getDescription()); - values.put(KEY_CONTENT_ENCODED, item.getContentEncoded()); + if (item.getDescription() != null) { + values.put(KEY_DESCRIPTION, item.getDescription()); + } + if (item.getContentEncoded() != null) { + values.put(KEY_CONTENT_ENCODED, item.getContentEncoded()); + } values.put(KEY_PUBDATE, item.getPubDate().getTime()); values.put(KEY_PAYMENT_LINK, item.getPaymentLink()); if (item.getMedia() != null) { @@ -471,7 +509,7 @@ public class PodDBAdapter { } /** - * Returns a cursor with all FeedItems of a Feed. + * Returns a cursor with all FeedItems of a Feed. Uses SEL_FI_SMALL * * @param feed * The feed you want to get the FeedItems from. @@ -479,9 +517,18 @@ public class PodDBAdapter { * */ public final Cursor getAllItemsOfFeedCursor(final Feed feed) { open(); + Cursor c = db.query(TABLE_NAME_FEED_ITEMS, SEL_FI_SMALL, KEY_FEED + + "=?", new String[] { String.valueOf(feed.getId()) }, null, + null, null); + return c; + } + + /** Return a cursor with the SEL_FI_EXTRA selection of a single feeditem. */ + public final Cursor getExtraInformationOfItem(final FeedItem item) { + open(); Cursor c = db - .query(TABLE_NAME_FEED_ITEMS, null, KEY_FEED + "=?", - new String[] { String.valueOf(feed.getId()) }, null, + .query(TABLE_NAME_FEED_ITEMS, SEL_FI_EXTRA, KEY_ID + "=?", + new String[] { String.valueOf(item.getId()) }, null, null, null); return c; } @@ -603,6 +650,47 @@ public class PodDBAdapter { return image; } + /** + * Searches for the given query in the description of all items or the items + * of a specified feed. + * + * @return A cursor with all search results in SEL_FI_EXTRA selection. + * */ + public Cursor searchItemDescriptions(Feed feed, String query) { + if (feed != null) { + // search items in specific feed + return db.query(TABLE_NAME_FEED_ITEMS, SEL_FI_EXTRA, KEY_FEED + + "=? AND " + KEY_DESCRIPTION + " LIKE '%" + query + "%'", new String[] { + String.valueOf(feed.getId()) }, null, null, null); + } else { + // search through all items + return db.query(TABLE_NAME_FEED_ITEMS, SEL_FI_EXTRA, + KEY_DESCRIPTION + " LIKE '%" + query + "%'", null, null, + null, null); + } + } + + /** + * Searches for the given query in the content-encoded field of all items or + * the items of a specified feed. + * + * @return A cursor with all search results in SEL_FI_EXTRA selection. + * */ + public Cursor searchItemContentEncoded(Feed feed, String query) { + if (feed != null) { + // search items in specific feed + return db.query(TABLE_NAME_FEED_ITEMS, SEL_FI_EXTRA, KEY_FEED + + "=? AND " + KEY_CONTENT_ENCODED + " LIKE '%" + query + "%'", + new String[] { String.valueOf(feed.getId())}, null, + null, null); + } else { + // search through all items + return db.query(TABLE_NAME_FEED_ITEMS, SEL_FI_EXTRA, + KEY_CONTENT_ENCODED + " LIKE '%" + query + "%'", null, + null, null, null); + } + } + /** Helper class for opening the Antennapod database. */ private static class PodDBHelper extends SQLiteOpenHelper { /** |