Searching descriptions should now work
This commit is contained in:
parent
a51e371fa4
commit
1cac6a2de9
|
@ -149,7 +149,7 @@ public class SearchActivity extends SherlockListActivity {
|
||||||
protected ArrayList<SearchResult> doInBackground(String... params) {
|
protected ArrayList<SearchResult> doInBackground(String... params) {
|
||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Starting background work");
|
Log.d(TAG, "Starting background work");
|
||||||
return FeedSearcher.performSearch(params[0], selectedFeed);
|
return FeedSearcher.performSearch(SearchActivity.this, params[0], selectedFeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1012,6 +1012,19 @@ public class FeedManager {
|
||||||
return null;
|
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 */
|
/** Get a FeedMedia object by the id of the Media object and the feed object */
|
||||||
public FeedMedia getFeedMedia(long id, Feed feed) {
|
public FeedMedia getFeedMedia(long id, Feed feed) {
|
||||||
if (feed != null) {
|
if (feed != null) {
|
||||||
|
@ -1346,32 +1359,28 @@ public class FeedManager {
|
||||||
|
|
||||||
public void searchFeedItemDescription(final Context context,
|
public void searchFeedItemDescription(final Context context,
|
||||||
final Feed feed, final String query,
|
final Feed feed, final String query,
|
||||||
FeedManager.TaskCallback callback) {
|
FeedManager.QueryTaskCallback callback) {
|
||||||
dbExec.execute(new FeedManager.Task(new Handler(), callback) {
|
dbExec.execute(new FeedManager.QueryTask(context, new Handler(), callback) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute(PodDBAdapter adapter) {
|
||||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
Cursor searchResult = adapter.searchItemDescriptions(feed,
|
||||||
adapter.open();
|
query);
|
||||||
Cursor searchResult = adapter.searchItemDescriptions(feed, query);
|
|
||||||
setResult(searchResult);
|
setResult(searchResult);
|
||||||
adapter.close();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void searchFeedItemContentEncoded(final Context context,
|
public void searchFeedItemContentEncoded(final Context context,
|
||||||
final Feed feed, final String query,
|
final Feed feed, final String query,
|
||||||
FeedManager.TaskCallback callback) {
|
FeedManager.QueryTaskCallback callback) {
|
||||||
dbExec.execute(new FeedManager.Task(new Handler(), callback) {
|
dbExec.execute(new FeedManager.QueryTask(context, new Handler(), callback) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute(PodDBAdapter adapter) {
|
||||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
Cursor searchResult = adapter.searchItemContentEncoded(feed,
|
||||||
adapter.open();
|
query);
|
||||||
Cursor searchResult = adapter.searchItemContentEncoded(feed, query);
|
|
||||||
setResult(searchResult);
|
setResult(searchResult);
|
||||||
adapter.close();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1400,15 +1409,18 @@ public class FeedManager {
|
||||||
public interface TaskCallback {
|
public interface TaskCallback {
|
||||||
void onCompletion(Cursor result);
|
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. */
|
/** A runnable that can post a callback to a handler after completion. */
|
||||||
abstract class Task implements Runnable {
|
abstract class Task implements Runnable {
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
private TaskCallback callback;
|
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
|
* Standard contructor. No callbacks are going to be posted to a
|
||||||
* handler.
|
* handler.
|
||||||
|
@ -1434,7 +1446,7 @@ public class FeedManager {
|
||||||
handler.post(new Runnable() {
|
handler.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
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. */
|
/** This method will be executed in the same thread as the run() method. */
|
||||||
public abstract void execute();
|
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) {
|
protected void setResult(Cursor c) {
|
||||||
result = c;
|
result = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,14 @@ import java.util.Collections;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.os.Looper;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import de.danoeh.antennapod.AppConfig;
|
import de.danoeh.antennapod.AppConfig;
|
||||||
import de.danoeh.antennapod.PodcastApp;
|
import de.danoeh.antennapod.PodcastApp;
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
|
import de.danoeh.antennapod.storage.PodDBAdapter;
|
||||||
import de.danoeh.antennapod.util.comparator.SearchResultValueComparator;
|
import de.danoeh.antennapod.util.comparator.SearchResultValueComparator;
|
||||||
|
|
||||||
/** Performs search on Feeds and FeedItems */
|
/** Performs search on Feeds and FeedItems */
|
||||||
|
@ -23,10 +27,10 @@ public class FeedSearcher {
|
||||||
private static final int VALUE_WORD_MATCH = 4;
|
private static final int VALUE_WORD_MATCH = 4;
|
||||||
|
|
||||||
/** Performs a search in all feeds or one specific feed. */
|
/** Performs a search in all feeds or one specific feed. */
|
||||||
public static ArrayList<SearchResult> performSearch(final String query,
|
public static ArrayList<SearchResult> performSearch(final Context context,
|
||||||
Feed selectedFeed) {
|
final String query, final Feed selectedFeed) {
|
||||||
String lcQuery = query.toLowerCase();
|
final String lcQuery = query.toLowerCase();
|
||||||
ArrayList<SearchResult> result = new ArrayList<SearchResult>();
|
final ArrayList<SearchResult> result = new ArrayList<SearchResult>();
|
||||||
if (selectedFeed == null) {
|
if (selectedFeed == null) {
|
||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Performing global search");
|
Log.d(TAG, "Performing global search");
|
||||||
|
@ -45,14 +49,40 @@ public class FeedSearcher {
|
||||||
Log.d(TAG, "Searching item-chaptertitles");
|
Log.d(TAG, "Searching item-chaptertitles");
|
||||||
searchFeedItemChapters(lcQuery, result, selectedFeed);
|
searchFeedItemChapters(lcQuery, result, selectedFeed);
|
||||||
|
|
||||||
if (AppConfig.DEBUG)
|
final FeedManager manager = FeedManager.getInstance();
|
||||||
Log.d(TAG, "Searching item descriptions");
|
Looper.prepare();
|
||||||
searchFeedItemDescription(lcQuery, result, selectedFeed);
|
manager.searchFeedItemDescription(context, selectedFeed, lcQuery,
|
||||||
|
new FeedManager.QueryTaskCallback() {
|
||||||
|
|
||||||
if (AppConfig.DEBUG)
|
@Override
|
||||||
Log.d(TAG, "Searching item content encoded data");
|
public void handleResult(Cursor cResult) {
|
||||||
searchFeedItemContentEncoded(lcQuery, result, selectedFeed);
|
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)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Sorting results");
|
Log.d(TAG, "Sorting results");
|
||||||
Collections.sort(result, new SearchResultValueComparator());
|
Collections.sort(result, new SearchResultValueComparator());
|
||||||
|
@ -127,61 +157,74 @@ public class FeedSearcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void searchFeedItemDescription(String query,
|
private static void searchFeedItemDescriptionCursor(String query,
|
||||||
ArrayList<SearchResult> destination, Feed selectedFeed) {
|
ArrayList<SearchResult> destination, Feed feed, Cursor cursor) {
|
||||||
FeedManager manager = FeedManager.getInstance();
|
FeedManager manager = FeedManager.getInstance();
|
||||||
if (selectedFeed == null) {
|
if (cursor.moveToFirst()) {
|
||||||
for (Feed feed : manager.getFeeds()) {
|
do {
|
||||||
searchFeedItemDescriptionSingleFeed(query, destination, feed);
|
final long itemId = cursor
|
||||||
}
|
.getLong(PodDBAdapter.IDX_FI_EXTRA_ID);
|
||||||
} else {
|
String content = cursor
|
||||||
searchFeedItemDescriptionSingleFeed(query, destination,
|
.getString(PodDBAdapter.IDX_FI_EXTRA_DESCRIPTION);
|
||||||
selectedFeed);
|
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);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} while (cursor.moveToNext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void searchFeedItemContentEncoded(String query,
|
private static void searchFeedItemContentEncodedCursor(String query,
|
||||||
ArrayList<SearchResult> destination, Feed selectedFeed) {
|
ArrayList<SearchResult> destination, Feed feed, Cursor cursor) {
|
||||||
FeedManager manager = FeedManager.getInstance();
|
FeedManager manager = FeedManager.getInstance();
|
||||||
if (selectedFeed == null) {
|
if (cursor.moveToFirst()) {
|
||||||
for (Feed feed : manager.getFeeds()) {
|
do {
|
||||||
searchFeedItemContentEncodedSingleFeed(query, destination, feed);
|
final long itemId = cursor
|
||||||
}
|
.getLong(PodDBAdapter.IDX_FI_EXTRA_ID);
|
||||||
} else {
|
String content = cursor
|
||||||
searchFeedItemContentEncodedSingleFeed(query, destination,
|
.getString(PodDBAdapter.IDX_FI_EXTRA_CONTENT_ENCODED);
|
||||||
selectedFeed);
|
if (content != null) {
|
||||||
}
|
content = content.toLowerCase();
|
||||||
}
|
|
||||||
|
|
||||||
private static void searchFeedItemContentEncodedSingleFeed(String query,
|
final long feedId = cursor
|
||||||
ArrayList<SearchResult> destination, Feed feed) {
|
.getLong(PodDBAdapter.IDX_FI_EXTRA_FEED);
|
||||||
for (FeedItem item : feed.getItems()) {
|
FeedItem item = null;
|
||||||
if (!destination.contains(item) && item.getContentEncoded() != null) {
|
if (feed == null) {
|
||||||
SearchResult result = createSearchResult(item, query, item
|
item = manager.getFeedItem(itemId, feedId);
|
||||||
.getContentEncoded().toLowerCase(),
|
} else {
|
||||||
VALUE_ITEM_DESCRIPTION);
|
item = manager.getFeedItem(itemId, feed);
|
||||||
if (result != null) {
|
}
|
||||||
result.setSubtitle(PodcastApp.getInstance().getString(
|
if (item != null) {
|
||||||
R.string.found_in_shownotes_label));
|
SearchResult searchResult = createSearchResult(item,
|
||||||
destination.add(result);
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -660,12 +660,12 @@ public class PodDBAdapter {
|
||||||
if (feed != null) {
|
if (feed != null) {
|
||||||
// search items in specific feed
|
// search items in specific feed
|
||||||
return db.query(TABLE_NAME_FEED_ITEMS, SEL_FI_EXTRA, KEY_FEED
|
return db.query(TABLE_NAME_FEED_ITEMS, SEL_FI_EXTRA, KEY_FEED
|
||||||
+ "=? AND " + KEY_DESCRIPTION + " LIKE ?", new String[] {
|
+ "=? AND " + KEY_DESCRIPTION + " LIKE '%" + query + "%'", new String[] {
|
||||||
String.valueOf(feed.getId()), query }, null, null, null);
|
String.valueOf(feed.getId()) }, null, null, null);
|
||||||
} else {
|
} else {
|
||||||
// search through all items
|
// search through all items
|
||||||
return db.query(TABLE_NAME_FEED_ITEMS, SEL_FI_EXTRA,
|
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);
|
null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -680,13 +680,13 @@ public class PodDBAdapter {
|
||||||
if (feed != null) {
|
if (feed != null) {
|
||||||
// search items in specific feed
|
// search items in specific feed
|
||||||
return db.query(TABLE_NAME_FEED_ITEMS, SEL_FI_EXTRA, KEY_FEED
|
return db.query(TABLE_NAME_FEED_ITEMS, SEL_FI_EXTRA, KEY_FEED
|
||||||
+ "=? AND " + KEY_CONTENT_ENCODED + " LIKE ?",
|
+ "=? AND " + KEY_CONTENT_ENCODED + " LIKE '%" + query + "%'",
|
||||||
new String[] { String.valueOf(feed.getId()), query }, null,
|
new String[] { String.valueOf(feed.getId())}, null,
|
||||||
null, null);
|
null, null);
|
||||||
} else {
|
} else {
|
||||||
// search through all items
|
// search through all items
|
||||||
return db.query(TABLE_NAME_FEED_ITEMS, SEL_FI_EXTRA,
|
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);
|
null, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue