diff options
-rw-r--r-- | src/de/danoeh/antennapod/activity/SearchActivity.java | 2 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/feed/FeedManager.java | 98 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/feed/FeedSearcher.java | 157 | ||||
-rw-r--r-- | src/de/danoeh/antennapod/storage/PodDBAdapter.java | 12 |
4 files changed, 183 insertions, 86 deletions
diff --git a/src/de/danoeh/antennapod/activity/SearchActivity.java b/src/de/danoeh/antennapod/activity/SearchActivity.java index a073b43cc..8bc38fa5b 100644 --- a/src/de/danoeh/antennapod/activity/SearchActivity.java +++ b/src/de/danoeh/antennapod/activity/SearchActivity.java @@ -149,7 +149,7 @@ public class SearchActivity extends SherlockListActivity { protected ArrayList<SearchResult> doInBackground(String... params) { if (AppConfig.DEBUG) Log.d(TAG, "Starting background work"); - return FeedSearcher.performSearch(params[0], selectedFeed); + return FeedSearcher.performSearch(SearchActivity.this, params[0], selectedFeed); } @Override diff --git a/src/de/danoeh/antennapod/feed/FeedManager.java b/src/de/danoeh/antennapod/feed/FeedManager.java index 479ce9732..285fc3539 100644 --- a/src/de/danoeh/antennapod/feed/FeedManager.java +++ b/src/de/danoeh/antennapod/feed/FeedManager.java @@ -1012,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) { @@ -1346,32 +1359,28 @@ public class FeedManager { public void searchFeedItemDescription(final Context context, final Feed feed, final String query, - FeedManager.TaskCallback callback) { - dbExec.execute(new FeedManager.Task(new Handler(), callback) { - + FeedManager.QueryTaskCallback callback) { + dbExec.execute(new FeedManager.QueryTask(context, new Handler(), callback) { + @Override - public void execute() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - Cursor searchResult = adapter.searchItemDescriptions(feed, query); + public void execute(PodDBAdapter adapter) { + Cursor searchResult = adapter.searchItemDescriptions(feed, + query); setResult(searchResult); - adapter.close(); } }); } - + public void searchFeedItemContentEncoded(final Context context, final Feed feed, final String query, - FeedManager.TaskCallback callback) { - dbExec.execute(new FeedManager.Task(new Handler(), callback) { - + FeedManager.QueryTaskCallback callback) { + dbExec.execute(new FeedManager.QueryTask(context, new Handler(), callback) { + @Override - public void execute() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - Cursor searchResult = adapter.searchItemContentEncoded(feed, query); + public void execute(PodDBAdapter adapter) { + Cursor searchResult = adapter.searchItemContentEncoded(feed, + query); setResult(searchResult); - adapter.close(); } }); } @@ -1400,15 +1409,18 @@ public class FeedManager { 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; - /** Can be used for returning database query results. */ - private Cursor result; - /** * Standard contructor. No callbacks are going to be posted to a * handler. @@ -1434,7 +1446,7 @@ public class FeedManager { handler.post(new Runnable() { @Override public void run() { - callback.onCompletion(result); + callback.onCompletion(null); } }); } @@ -1442,11 +1454,53 @@ public class FeedManager { /** 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/storage/PodDBAdapter.java b/src/de/danoeh/antennapod/storage/PodDBAdapter.java index 9026ad653..9b60521cf 100644 --- a/src/de/danoeh/antennapod/storage/PodDBAdapter.java +++ b/src/de/danoeh/antennapod/storage/PodDBAdapter.java @@ -660,12 +660,12 @@ public class PodDBAdapter { if (feed != null) { // search items in specific feed return db.query(TABLE_NAME_FEED_ITEMS, SEL_FI_EXTRA, KEY_FEED - + "=? AND " + KEY_DESCRIPTION + " LIKE ?", new String[] { - String.valueOf(feed.getId()), query }, null, null, null); + + "=? 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 ?", new String[] { query }, null, + KEY_DESCRIPTION + " LIKE '%" + query + "%'", null, null, null, null); } } @@ -680,13 +680,13 @@ public class PodDBAdapter { 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 ?", - new String[] { String.valueOf(feed.getId()), query }, null, + + "=? 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 ?", new String[] { query }, + KEY_CONTENT_ENCODED + " LIKE '%" + query + "%'", null, null, null, null); } } |