diff options
13 files changed, 162 insertions, 84 deletions
diff --git a/src/com/android/quicksearchbox/CursorBackedSuggestionCursor.java b/src/com/android/quicksearchbox/CursorBackedSuggestionCursor.java index 024310a..179542f 100644 --- a/src/com/android/quicksearchbox/CursorBackedSuggestionCursor.java +++ b/src/com/android/quicksearchbox/CursorBackedSuggestionCursor.java @@ -290,4 +290,9 @@ public abstract class CursorBackedSuggestionCursor implements SuggestionCursor { // We don't watch Cursor-backed SuggestionCursors for changes } + @Override + public String toString() { + return getClass().getSimpleName() + "[" + mUserQuery + "]"; + } + } diff --git a/src/com/android/quicksearchbox/ListSuggestionCursor.java b/src/com/android/quicksearchbox/ListSuggestionCursor.java index 313f50c..d2a6034 100644 --- a/src/com/android/quicksearchbox/ListSuggestionCursor.java +++ b/src/com/android/quicksearchbox/ListSuggestionCursor.java @@ -18,6 +18,7 @@ package com.android.quicksearchbox; import android.database.DataSetObservable; import android.database.DataSetObserver; +import android.util.Log; import java.util.ArrayList; @@ -53,7 +54,6 @@ public class ListSuggestionCursor extends AbstractSuggestionCursorWrapper { /** * Adds a suggestion from another suggestion cursor. * - * @param suggestionPos * @return {@code true} if the suggestion was added. */ public boolean add(Suggestion suggestion) { @@ -102,7 +102,7 @@ public class ListSuggestionCursor extends AbstractSuggestionCursorWrapper { @Override public String toString() { - return "[" + getUserQuery() + "] " + mSuggestions; + return getClass().getSimpleName() + "{[" + getUserQuery() + "] " + mSuggestions + "}"; } /** diff --git a/src/com/android/quicksearchbox/ShortcutCursor.java b/src/com/android/quicksearchbox/ShortcutCursor.java index ecbde97..ae800d9 100644 --- a/src/com/android/quicksearchbox/ShortcutCursor.java +++ b/src/com/android/quicksearchbox/ShortcutCursor.java @@ -16,6 +16,7 @@ package com.android.quicksearchbox; +import android.os.Handler; import android.util.Log; import java.util.HashSet; @@ -30,23 +31,42 @@ class ShortcutCursor extends ListSuggestionCursor { private static final String TAG = "QSB.ShortcutCursor"; // mShortcuts is used to close the underlying cursor when we're closed. - private final CursorBackedSuggestionCursor mShortcuts; + private final SuggestionCursor mShortcuts; // mRefreshed contains all the cursors that have been refreshed, so that // they can be closed when ShortcutCursor is closed. private final HashSet<SuggestionCursor> mRefreshed; + private final ShortcutRefresher mRefresher; + private final ShortcutRepository mShortcutRepo; + private final Handler mUiThread; + private boolean mClosed; - public ShortcutCursor(CursorBackedSuggestionCursor shortcuts) { - super(shortcuts.getUserQuery()); + private ShortcutCursor(String query, SuggestionCursor shortcuts, Handler uiThread, + ShortcutRefresher refresher, ShortcutRepository repository) { + super(query); mShortcuts = shortcuts; + mUiThread = uiThread; + mRefresher = refresher; + mShortcutRepo = repository; mRefreshed = new HashSet<SuggestionCursor>(); - int count = shortcuts.getCount(); + } + + public ShortcutCursor(String query, Handler uiThread, + ShortcutRefresher refresher, ShortcutRepository repository) { + this(query, null, uiThread, refresher, repository); + } + + public ShortcutCursor(SuggestionCursor suggestions, Handler uiThread, + ShortcutRefresher refresher, ShortcutRepository repository) { + this(suggestions.getUserQuery(), suggestions, uiThread, refresher, repository); + if (suggestions == null) return; + int count = suggestions.getCount(); if (DBG) Log.d(TAG, "Total shortcuts: " + count); for (int i = 0; i < count; i++) { - shortcuts.moveTo(i); - if (shortcuts.getSuggestionSource() != null) { - add(new SuggestionPosition(shortcuts)); + suggestions.moveTo(i); + if (suggestions.getSuggestionSource() != null) { + add(new SuggestionPosition(suggestions)); } else { if (DBG) Log.d(TAG, "Skipping shortcut " + i); } @@ -54,11 +74,31 @@ class ShortcutCursor extends ListSuggestionCursor { } /** + * Refresh a shortcut from this cursor. + * + * @param shortcut The shotrcut to refresh. Should be a shortcut taken from this cursor. + */ + public void refresh(Suggestion shortcut) { + mRefresher.refresh(shortcut, new ShortcutRefresher.Listener() { + public void onShortcutRefreshed(final Source source, + final String shortcutId, final SuggestionCursor refreshed) { + if (DBG) Log.d(TAG, "Shortcut refreshed: " + shortcutId); + mShortcutRepo.updateShortcut(source, shortcutId, refreshed); + mUiThread.post(new Runnable() { + public void run() { + refresh(source, shortcutId, refreshed); + } + }); + } + }); + } + + /** * Updates this SuggestionCursor with a refreshed result from another. * Since this modifies the cursor, it should be called on the UI thread. * This class assumes responsibility for closing refreshed. */ - public void refresh(Source source, String shortcutId, SuggestionCursor refreshed) { + private void refresh(Source source, String shortcutId, SuggestionCursor refreshed) { if (DBG) Log.d(TAG, "refresh " + shortcutId); if (mClosed) { if (refreshed != null) { @@ -72,13 +112,15 @@ class ShortcutCursor extends ListSuggestionCursor { for (int i = 0; i < getCount(); i++) { moveTo(i); if (shortcutId.equals(getShortcutId()) && source.equals(getSuggestionSource())) { - if (refreshed != null && refreshed.getCount() > 0) { - replaceRow(new SuggestionPosition(refreshed)); - } else { - removeRow(); - } - notifyDataSetChanged(); - break; + if (refreshed != null && refreshed.getCount() > 0) { + if (DBG) Log.d(TAG, "replacing row " + i); + replaceRow(new SuggestionPosition(refreshed)); + } else { + if (DBG) Log.d(TAG, "removing row " + i); + removeRow(); + } + notifyDataSetChanged(); + break; } } } @@ -89,8 +131,11 @@ class ShortcutCursor extends ListSuggestionCursor { if (mClosed) { throw new IllegalStateException("Double close()"); } + super.close(); mClosed = true; - mShortcuts.close(); + if (mShortcuts != null) { + mShortcuts.close(); + } for (SuggestionCursor cursor : mRefreshed) { cursor.close(); } diff --git a/src/com/android/quicksearchbox/ShortcutLimitingPromoter.java b/src/com/android/quicksearchbox/ShortcutLimitingPromoter.java index 11068c1..727878a 100644 --- a/src/com/android/quicksearchbox/ShortcutLimitingPromoter.java +++ b/src/com/android/quicksearchbox/ShortcutLimitingPromoter.java @@ -60,15 +60,17 @@ public class ShortcutLimitingPromoter extends PromoterWrapper { for (int i = 0; i < shortcutCount; i++) { shortcuts.moveTo(i); Source source = shortcuts.getSuggestionSource(); - int prevCount = sourceShortcutCounts.add(source, 1); - if (DBG) Log.d(TAG, "Source: " + source + ", count: " + prevCount); - int maxShortcuts = source.isWebSuggestionSource() - ? mMaxShortcutsPerWebSource : mMaxShortcutsPerNonWebSource; - if (prevCount < maxShortcuts) { - numPromoted++; - filteredShortcuts.add(new SuggestionPosition(shortcuts)); + if (source != null) { + int prevCount = sourceShortcutCounts.add(source, 1); + if (DBG) Log.d(TAG, "Source: " + source + ", count: " + prevCount); + int maxShortcuts = source.isWebSuggestionSource() + ? mMaxShortcutsPerWebSource : mMaxShortcutsPerNonWebSource; + if (prevCount < maxShortcuts) { + numPromoted++; + filteredShortcuts.add(new SuggestionPosition(shortcuts)); + } + if (numPromoted >= maxPromoted) break; } - if (numPromoted >= maxPromoted) break; } } if (DBG) { diff --git a/src/com/android/quicksearchbox/ShortcutRefresher.java b/src/com/android/quicksearchbox/ShortcutRefresher.java index 083b1aa..e951069 100644 --- a/src/com/android/quicksearchbox/ShortcutRefresher.java +++ b/src/com/android/quicksearchbox/ShortcutRefresher.java @@ -16,6 +16,8 @@ package com.android.quicksearchbox; +import com.android.quicksearchbox.ShortcutRefresher.Listener; + /** * Fires off tasks to validate shortcuts, and reports the results back to a * {@link Listener}. @@ -36,12 +38,12 @@ public interface ShortcutRefresher { } /** - * Sends off the refresher tasks. + * Starts a task to refresh a single shortcut. * - * @param shortcuts The shortcuts to refresh. + * @param shortcut The shortcut to be refreshed. * @param listener Who to report back to. */ - void refresh(SuggestionCursor shortcuts, final Listener listener); + void refresh(Suggestion shortcut, Listener listener); /** * Returns true if the given shortcut requires refreshing. diff --git a/src/com/android/quicksearchbox/ShortcutRepository.java b/src/com/android/quicksearchbox/ShortcutRepository.java index 7f163ab..256b489 100644 --- a/src/com/android/quicksearchbox/ShortcutRepository.java +++ b/src/com/android/quicksearchbox/ShortcutRepository.java @@ -53,7 +53,16 @@ public interface ShortcutRepository { * @param allowedCorpora The corpora to get shortcuts for. * @return A cursor containing shortcutted results for the query. */ - SuggestionCursor getShortcutsForQuery(String query, Collection<Corpus> allowedCorpora); + ShortcutCursor getShortcutsForQuery(String query, Collection<Corpus> allowedCorpora); + + /** + * Updates a shortcut in the repository after it's been refreshed. + * + * @param source The source of the shortcut that's been refreshed + * @param shortcutId The ID of the shortcut that's been refershed + * @param refreshed The refreshed shortcut suggestion. + */ + void updateShortcut(Source source, String shortcutId, SuggestionCursor refreshed); /** * @return A map for corpus name to score. A higher score means that the corpus diff --git a/src/com/android/quicksearchbox/ShortcutRepositoryImplLog.java b/src/com/android/quicksearchbox/ShortcutRepositoryImplLog.java index af93d9b..b71d3f0 100644 --- a/src/com/android/quicksearchbox/ShortcutRepositoryImplLog.java +++ b/src/com/android/quicksearchbox/ShortcutRepositoryImplLog.java @@ -249,16 +249,17 @@ public class ShortcutRepositoryImplLog implements ShortcutRepository { reportClickAtTime(suggestions, position, now); } - public SuggestionCursor getShortcutsForQuery(String query, Collection<Corpus> allowedCorpora) { + public ShortcutCursor getShortcutsForQuery(String query, Collection<Corpus> allowedCorpora) { ShortcutCursor shortcuts = getShortcutsForQuery(query, allowedCorpora, System.currentTimeMillis()); mUpdateScheduler.delayUpdates(); - if (shortcuts != null) { - startRefresh(shortcuts); - } return shortcuts; } + public void updateShortcut(Source source, String shortcutId, SuggestionCursor refreshed) { + refreshShortcut(source, shortcutId, refreshed); + } + public Map<String,Integer> getCorpusScores() { return getCorpusScores(mConfig.getMinClicksForSourceRanking()); } @@ -292,21 +293,8 @@ public class ShortcutRepositoryImplLog implements ShortcutRepository { } } - return new ShortcutCursor(new SuggestionCursorImpl(allowedSources, query, cursor)); - } - - private void startRefresh(final ShortcutCursor shortcuts) { - mRefresher.refresh(shortcuts, new ShortcutRefresher.Listener() { - public void onShortcutRefreshed(final Source source, - final String shortcutId, final SuggestionCursor refreshed) { - refreshShortcut(source, shortcutId, refreshed); - mUiThread.post(new Runnable() { - public void run() { - shortcuts.refresh(source, shortcutId, refreshed); - } - }); - } - }); + return new ShortcutCursor(new SuggestionCursorImpl(allowedSources, query, cursor), + mUiThread, mRefresher, this); } @VisibleForTesting @@ -361,7 +349,7 @@ public class ShortcutRepositoryImplLog implements ShortcutRepository { if (source == null) { if (DBG) { Log.d(TAG, "Source " + srcStr + " (position " + mCursor.getPosition() + - " not allowed"); + ") not allowed"); } return null; } @@ -379,8 +367,10 @@ public class ShortcutRepositoryImplLog implements ShortcutRepository { @Override public String getSuggestionIcon2() { if (isSpinnerWhileRefreshing() && shouldRefresh(this)) { + if (DBG) Log.d(TAG, "shortcut " + getShortcutId() + " refreshing"); return mSearchSpinner; } + if (DBG) Log.d(TAG, "shortcut " + getShortcutId() + " NOT refreshing"); return super.getSuggestionIcon2(); } @@ -388,15 +378,10 @@ public class ShortcutRepositoryImplLog implements ShortcutRepository { return true; } - @Override - public String toString() { - return "shortcuts[" + getUserQuery() + "]"; - } - } /** - * Builds a parameter list for the query returned by {@link #buildShortcutQuery(boolean)}. + * Builds a parameter list for the queries built by {@link #buildShortcutQueries}. */ private static String[] buildShortcutQueryParams(String query, long now) { return new String[]{ query, nextString(query), String.valueOf(now) }; diff --git a/src/com/android/quicksearchbox/SourceShortcutRefresher.java b/src/com/android/quicksearchbox/SourceShortcutRefresher.java index e520964..540c3e2 100644 --- a/src/com/android/quicksearchbox/SourceShortcutRefresher.java +++ b/src/com/android/quicksearchbox/SourceShortcutRefresher.java @@ -19,6 +19,8 @@ package com.android.quicksearchbox; import com.android.quicksearchbox.util.NamedTask; import com.android.quicksearchbox.util.NamedTaskExecutor; +import android.util.Log; + import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -27,10 +29,13 @@ import java.util.Set; * Refreshes shortcuts from their source. */ class SourceShortcutRefresher implements ShortcutRefresher { + private static final String TAG = "QSB.SourceShortcutRefresher"; + private static final boolean DBG = false; private final NamedTaskExecutor mExecutor; private final Set<String> mRefreshed = Collections.synchronizedSet(new HashSet<String>()); + private final Set<String> mRefreshing = Collections.synchronizedSet(new HashSet<String>()); /** * Create a ShortcutRefresher that will refresh shortcuts using the given executor. @@ -41,27 +46,22 @@ class SourceShortcutRefresher implements ShortcutRefresher { mExecutor = executor; } - /** - * Sends off the refresher tasks. - * - * @param shortcuts The shortcuts to refresh. - * @param listener Who to report back to. - */ - public void refresh(SuggestionCursor shortcuts, final Listener listener) { - int count = shortcuts.getCount(); - for (int i = 0; i < count; i++) { - shortcuts.moveTo(i); - Source source = shortcuts.getSuggestionSource(); - if (source == null) { - throw new NullPointerException("source"); - } - String shortcutId = shortcuts.getShortcutId(); - if (shouldRefresh(source, shortcutId)) { - String extraData = shortcuts.getSuggestionIntentExtraData(); - ShortcutRefreshTask refreshTask = new ShortcutRefreshTask( - source, shortcutId, extraData, listener); - mExecutor.execute(refreshTask); + public void refresh(Suggestion shortcut, Listener listener) { + Source source = shortcut.getSuggestionSource(); + if (source == null) { + throw new NullPointerException("source"); + } + String shortcutId = shortcut.getShortcutId(); + if (shouldRefresh(source, shortcutId) && !isRefreshing(source, shortcutId)) { + if (DBG) { + Log.d(TAG, "Refreshing shortcut " + shortcutId + " '" + + shortcut.getSuggestionText1() + "'"); } + markShortcutRefreshing(source, shortcutId); + String extraData = shortcut.getSuggestionIntentExtraData(); + ShortcutRefreshTask refreshTask = new ShortcutRefreshTask( + source, shortcutId, extraData, listener); + mExecutor.execute(refreshTask); } } @@ -73,11 +73,22 @@ class SourceShortcutRefresher implements ShortcutRefresher { && !mRefreshed.contains(makeKey(source, shortcutId)); } + public boolean isRefreshing(Source source, String shortcutId) { + return source != null && shortcutId != null + && mRefreshing.contains(makeKey(source, shortcutId)); + } + + private void markShortcutRefreshing(Source source, String shortcutId) { + mRefreshing.add(makeKey(source, shortcutId)); + } + /** * Indicate that the shortcut no longer requires refreshing. */ public void markShortcutRefreshed(Source source, String shortcutId) { - mRefreshed.add(makeKey(source, shortcutId)); + String key = makeKey(source, shortcutId); + mRefreshed.add(key); + mRefreshing.remove(key); } /** diff --git a/src/com/android/quicksearchbox/Suggestions.java b/src/com/android/quicksearchbox/Suggestions.java index e557c06..e1fcd13 100644 --- a/src/com/android/quicksearchbox/Suggestions.java +++ b/src/com/android/quicksearchbox/Suggestions.java @@ -60,7 +60,7 @@ public class Suggestions { * */ private final ArrayList<CorpusResult> mCorpusResults; - private SuggestionCursor mShortcuts; + private ShortcutCursor mShortcuts; private final MyShortcutsObserver mShortcutsObserver = new MyShortcutsObserver(); @@ -130,6 +130,7 @@ public class Suggestions { if (mPromoted == null) { updatePromoted(); } + if (DBG) Log.d(TAG, "getPromoted() = " + mPromoted); return mPromoted; } @@ -200,7 +201,7 @@ public class Suggestions { * * @param shortcuts The shortcuts. */ - public void setShortcuts(SuggestionCursor shortcuts) { + public void setShortcuts(ShortcutCursor shortcuts) { if (DBG) Log.d(TAG, "setShortcuts(" + shortcuts + ")"); mShortcuts = shortcuts; if (shortcuts != null) { @@ -247,6 +248,7 @@ public class Suggestions { Log.d(TAG, "pickPromoted(" + mShortcuts + "," + mCorpusResults + "," + mMaxPromoted + ") = " + mPromoted); } + refreshShortcuts(); } else { mPromoted = getCorpusResult(mSingleCorpusFilter); if (mPromoted == null) { @@ -255,6 +257,17 @@ public class Suggestions { } } + private void refreshShortcuts() { + if (DBG) Log.d(TAG, "refreshShortcuts(" + mPromoted + ")"); + for (int i = 0; i < mPromoted.getCount(); ++i) { + mPromoted.moveTo(i); + if (mPromoted.isSuggestionShortcut()) { + mShortcuts.refresh(mPromoted); + } + } + } + + private CorpusResult getCorpusResult(Corpus corpus) { for (CorpusResult result : mCorpusResults) { if (result.getCorpus().equals(mSingleCorpusFilter)) { diff --git a/src/com/android/quicksearchbox/SuggestionsProviderImpl.java b/src/com/android/quicksearchbox/SuggestionsProviderImpl.java index 78f5c1f..d6acca1 100644 --- a/src/com/android/quicksearchbox/SuggestionsProviderImpl.java +++ b/src/com/android/quicksearchbox/SuggestionsProviderImpl.java @@ -105,7 +105,7 @@ public class SuggestionsProviderImpl implements SuggestionsProvider { } } - protected SuggestionCursor getShortcutsForQuery(String query, Corpus singleCorpus) { + protected ShortcutCursor getShortcutsForQuery(String query, Corpus singleCorpus) { if (mShortcutRepo == null) return null; Collection<Corpus> allowedCorpora; if (singleCorpus == null) { @@ -160,7 +160,7 @@ public class SuggestionsProviderImpl implements SuggestionsProvider { maxSuggestions, query, corporaToQuery); - SuggestionCursor shortcuts = getShortcutsForQuery(query, singleCorpus); + ShortcutCursor shortcuts = getShortcutsForQuery(query, singleCorpus); if (shortcuts != null) { suggestions.setShortcuts(shortcuts); } diff --git a/src/com/android/quicksearchbox/google/GoogleSuggestClient.java b/src/com/android/quicksearchbox/google/GoogleSuggestClient.java index 242efd2..e903a5c 100644 --- a/src/com/android/quicksearchbox/google/GoogleSuggestClient.java +++ b/src/com/android/quicksearchbox/google/GoogleSuggestClient.java @@ -72,10 +72,12 @@ public class GoogleSuggestClient extends GoogleSource { mSuggestUri = null; } + @Override public ComponentName getIntentComponent() { return new ComponentName(getContext(), GoogleSearch.class); } + @Override public boolean isLocationAware() { return false; } @@ -165,6 +167,7 @@ public class GoogleSuggestClient extends GoogleSource { return null; } + @Override public SuggestionCursor refreshShortcut(String shortcutId, String oldExtraData) { return null; } diff --git a/tests/src/com/android/quicksearchbox/MockShortcutRefresher.java b/tests/src/com/android/quicksearchbox/MockShortcutRefresher.java index 9fb417b..d5c1f11 100644 --- a/tests/src/com/android/quicksearchbox/MockShortcutRefresher.java +++ b/tests/src/com/android/quicksearchbox/MockShortcutRefresher.java @@ -28,7 +28,7 @@ public class MockShortcutRefresher implements ShortcutRefresher { public void markShortcutRefreshed(Source source, String shortcutId) { } - public void refresh(SuggestionCursor shortcuts, Listener listener) { + public void refresh(Suggestion shortcut, Listener listener) { } public void reset() { diff --git a/tests/src/com/android/quicksearchbox/MockShortcutRepository.java b/tests/src/com/android/quicksearchbox/MockShortcutRepository.java index 6ccb1dc..ff8cbce 100644 --- a/tests/src/com/android/quicksearchbox/MockShortcutRepository.java +++ b/tests/src/com/android/quicksearchbox/MockShortcutRepository.java @@ -31,14 +31,17 @@ public class MockShortcutRepository implements ShortcutRepository { public void close() { } - public SuggestionCursor getShortcutsForQuery(String query, Collection<Corpus> corporaToQuery) { + public ShortcutCursor getShortcutsForQuery(String query, Collection<Corpus> corporaToQuery) { // TODO: should look at corporaToQuery - ListSuggestionCursor cursor = new ListSuggestionCursor(query); + ShortcutCursor cursor = new ShortcutCursor(query, null, null, null); cursor.add(MockSource.SOURCE_1.createSuggestion(query + "_1_shortcut")); cursor.add(MockSource.SOURCE_2.createSuggestion(query + "_2_shortcut")); return cursor; } + public void updateShortcut(Source source, String shortcutId, SuggestionCursor refreshed) { + } + public Map<String, Integer> getCorpusScores() { return null; } |