13e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/* 2848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani * Copyright (C) 2010 The Android Open Source Project 33e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 43e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); 53e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * you may not use this file except in compliance with the License. 63e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * You may obtain a copy of the License at 73e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 83e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0 93e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Unless required by applicable law or agreed to in writing, software 113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS, 123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * See the License for the specific language governing permissions and 143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * limitations under the License. 153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpackage com.android.quicksearchbox; 183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 19b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringertimport com.google.common.annotations.VisibleForTesting; 20b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.database.DataSetObservable; 223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.database.DataSetObserver; 233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.util.Log; 243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 25b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringertimport java.util.ArrayList; 2600efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwoodimport java.util.Arrays; 2700efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwoodimport java.util.HashMap; 28b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringertimport java.util.HashSet; 29b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringertimport java.util.List; 30b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringertimport java.util.Set; 31b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 32b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert/** 33b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Collects all corpus results for a single query. 34b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert */ 35b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringertpublic class Suggestions { 36cef2c4c9d54f513babd74801dbed5cbf709b9b79Bjorn Bringert private static final boolean DBG = false; 373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private static final String TAG = "QSB.Suggestions"; 383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 39848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani /** True if {@link Suggestions#close} has been called. */ 40848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani private boolean mClosed = false; 41848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani protected final String mQuery; 423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 434572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood private ShortcutCursor mShortcuts; 444572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood 454572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood private final MyShortcutsObserver mShortcutsObserver = new MyShortcutsObserver(); 464572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood 473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * The observers that want notifications of changes to the published suggestions. 493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * This object may be accessed on any thread. 503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final DataSetObservable mDataSetObservable = new DataSetObservable(); 523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 53b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert /** The sources that are expected to report. */ 54b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert private final List<Corpus> mExpectedCorpora; 5500efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood private final HashMap<String, Integer> mCorpusPositions; 56b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 57b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert /** 58b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * All {@link SuggestionCursor} objects that have been published so far, 5900efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood * in the same order as {@link #mExpectedCorpora}. There may be {@code null} items 6000efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood * in the array, if not all corpora have published yet. 61b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * This object may only be accessed on the UI thread. 62b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * */ 6300efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood private final CorpusResult[] mCorpusResults; 64b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 65b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert private CorpusResult mWebResult; 66b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 67b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert private int mRefCount = 0; 68b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 693540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert private boolean mDone = false; 703540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert 71b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public Suggestions(String query, List<Corpus> expectedCorpora) { 723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQuery = query; 73b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert mExpectedCorpora = expectedCorpora; 7400efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood mCorpusResults = new CorpusResult[mExpectedCorpora.size()]; 7500efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood // create a map of corpus name -> position in mExpectedCorpora for sorting later 7600efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood // (we want to keep the ordering of corpora in mCorpusResults). 7700efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood mCorpusPositions = new HashMap<String, Integer>(); 7800efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood for (int i = 0; i < mExpectedCorpora.size(); ++i) { 7900efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood mCorpusPositions.put(mExpectedCorpora.get(i).getName(), i); 8000efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood } 81b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert if (DBG) { 82b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert Log.d(TAG, "new Suggestions [" + hashCode() + "] query \"" + query 83b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert + "\" expected corpora: " + mExpectedCorpora); 84b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 85b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 86b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 87b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public void acquire() { 88b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert mRefCount++; 89b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 90b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 91b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public void release() { 92b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert mRefCount--; 93b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert if (mRefCount <= 0) { 94b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert close(); 95b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 96b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 97b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 98b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public List<Corpus> getExpectedCorpora() { 99b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert return mExpectedCorpora; 1004572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood } 1014572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood 102b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert /** 103b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Gets the number of corpora that are expected to report. 104b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert */ 105b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert @VisibleForTesting 106b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public int getExpectedResultCount() { 107b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert return mExpectedCorpora.size(); 108b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 109b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 110dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert public boolean expectsCorpus(Corpus corpus) { 111dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert for (Corpus expectedCorpus : mExpectedCorpora) { 112dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert if (expectedCorpus.equals(corpus)) return true; 113dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert } 114dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert return false; 115dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert } 116dfc1772caf35942837d83331d787eb10734c37cbBjorn Bringert 117b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert /** 118b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Gets the set of corpora that have reported results to this suggestions set. 119b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * 120b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * @return A collection of corpora. 121b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert */ 122b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public Set<Corpus> getIncludedCorpora() { 123b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert HashSet<Corpus> corpora = new HashSet<Corpus>(); 124b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert for (CorpusResult result : mCorpusResults) { 125116affd19a834a2df4226a1ae37afcc1113a230eMathew Inwood if (result != null) { 126116affd19a834a2df4226a1ae37afcc1113a230eMathew Inwood corpora.add(result.getCorpus()); 127116affd19a834a2df4226a1ae37afcc1113a230eMathew Inwood } 1284572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood } 129b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert return corpora; 1304572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood } 1314572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood 1324572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood /** 1334572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood * Sets the shortcut suggestions. 1344572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood * Must be called on the UI thread, or before this object is seen by the UI thread. 1354572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood * 1364572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood * @param shortcuts The shortcuts. 1374572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood */ 1384572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood public void setShortcuts(ShortcutCursor shortcuts) { 1394572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood if (DBG) Log.d(TAG, "setShortcuts(" + shortcuts + ")"); 140b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert if (mShortcuts != null) { 141b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert throw new IllegalStateException("Got duplicate shortcuts: old: " + mShortcuts 142b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert + ", new: " + shortcuts); 143b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert } 144b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert if (shortcuts == null) return; 145b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert if (isClosed()) { 146b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert shortcuts.close(); 147b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert return; 148b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert } 149b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert if (!mQuery.equals(shortcuts.getUserQuery())) { 150b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert throw new IllegalArgumentException("Got shortcuts for wrong query: " 151b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert + mQuery + " != " + shortcuts.getUserQuery()); 152b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert } 1534572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood mShortcuts = shortcuts; 1544572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood if (shortcuts != null) { 1554572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood mShortcuts.registerDataSetObserver(mShortcutsObserver); 1564572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood } 157b42184f1e6a1b7bb22797ff92cae696753aca770Bjorn Bringert notifyDataSetChanged(); 1583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 1613540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert * Marks the suggestions set as complete, regardless of whether all corpora have 1623540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert * returned. 1633540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert */ 1643540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert public void done() { 1653540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert mDone = true; 1663540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert } 1673540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert 1683540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert /** 169b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Checks whether all sources have reported. 170b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Must be called on the UI thread, or before this object is seen by the UI thread. 171b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert */ 172b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public boolean isDone() { 173b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert // TODO: Handle early completion because we have all the results we want. 17400efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood return mDone || countCorpusResults() >= mExpectedCorpora.size(); 17500efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood } 17600efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood 17700efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood private int countCorpusResults() { 17800efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood int count = 0; 17900efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood for (int i = 0; i < mCorpusResults.length; ++i) { 18000efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood if (mCorpusResults[i] != null) { 18100efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood count++; 18200efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood } 18300efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood } 18400efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood return count; 185b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 186b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 187b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert /** 188b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Adds a list of corpus results. Must be called on the UI thread, or before this 189b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * object is seen by the UI thread. 190b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert */ 191b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public void addCorpusResults(List<CorpusResult> corpusResults) { 192b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert if (isClosed()) { 193b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert for (CorpusResult corpusResult : corpusResults) { 194b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert corpusResult.close(); 195b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 196b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert return; 197b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 198b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 199b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert for (CorpusResult corpusResult : corpusResults) { 200b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert if (DBG) { 201b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert Log.d(TAG, "addCorpusResult["+ hashCode() + "] corpus:" + 202b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert corpusResult.getCorpus().getName() + " results:" + corpusResult.getCount()); 203b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 204b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert if (!mQuery.equals(corpusResult.getUserQuery())) { 205b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert throw new IllegalArgumentException("Got result for wrong query: " 206b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert + mQuery + " != " + corpusResult.getUserQuery()); 207b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 20800efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood Integer pos = mCorpusPositions.get(corpusResult.getCorpus().getName()); 20900efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood if (pos == null) { 21000efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood Log.w(TAG, "Got unexpected CorpusResult from corpus " + 21100efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood corpusResult.getCorpus().getName()); 21200efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood corpusResult.close(); 21300efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood } else { 21400efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood mCorpusResults[pos] = corpusResult; 21500efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood if (corpusResult.getCorpus().isWebCorpus()) { 21600efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood mWebResult = corpusResult; 21700efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood } 218b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 219b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 220b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert notifyDataSetChanged(); 221b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 222b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 223b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert /** 2243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Registers an observer that will be notified when the reported results or 2253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * the done status changes. 2263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 2273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void registerDataSetObserver(DataSetObserver observer) { 2283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mClosed) { 2293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert throw new IllegalStateException("registerDataSetObserver() when closed"); 2303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mDataSetObservable.registerObserver(observer); 2323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 234848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani 2353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 2363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Unregisters an observer. 2373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 2383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void unregisterDataSetObserver(DataSetObserver observer) { 2393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mDataSetObservable.unregisterObserver(observer); 2403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 242e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringert /** 2433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Calls {@link DataSetObserver#onChanged()} on all observers. 2443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 245848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani protected void notifyDataSetChanged() { 2463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "notifyDataSetChanged()"); 2473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mDataSetObservable.notifyChanged(); 2483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 250b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert /** 251b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Closes all the source results and unregisters all observers. 252b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert */ 253b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert private void close() { 254b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert if (DBG) Log.d(TAG, "close() [" + hashCode() + "]"); 2553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mClosed) { 256185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert throw new IllegalStateException("Double close()"); 2573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mClosed = true; 259848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani mDataSetObservable.unregisterAll(); 2604572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood if (mShortcuts != null) { 2614572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood mShortcuts.close(); 2624572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood mShortcuts = null; 2634572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood } 264b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 265b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert for (CorpusResult result : mCorpusResults) { 26600efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood if (result != null) { 26700efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood result.close(); 26800efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood } 269b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 27000efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood Arrays.fill(mCorpusResults, null); 2713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 27327d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney public boolean isClosed() { 27427d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney return mClosed; 27527d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney } 27627d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney 2778b2936607176720172aee068abc5631bdf77e843Bjorn Bringert public ShortcutCursor getShortcuts() { 2784572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood return mShortcuts; 2794572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood } 2804572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood 281b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert private void refreshShortcuts(SuggestionCursor promoted) { 282b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert if (DBG) Log.d(TAG, "refreshShortcuts(" + promoted + ")"); 283b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert for (int i = 0; i < promoted.getCount(); ++i) { 284b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert promoted.moveTo(i); 285b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert if (promoted.isSuggestionShortcut()) { 286b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert getShortcuts().refresh(promoted); 2874572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood } 2884572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood } 2894572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood } 2904572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood 2913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 2923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void finalize() { 2933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (!mClosed) { 294848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani Log.e(TAG, "LEAK! Finalized without being closed: Suggestions[" + getQuery() + "]"); 2953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 298848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani public String getQuery() { 299848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani return mQuery; 300ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert } 301ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert 302b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public SuggestionCursor getPromoted(Promoter promoter, int maxPromoted) { 303b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert SuggestionCursor promoted = buildPromoted(promoter, maxPromoted); 304b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert refreshShortcuts(promoted); 305b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert return promoted; 306b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 307b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 308b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert protected SuggestionCursor buildPromoted(Promoter promoter, int maxPromoted) { 309b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert ListSuggestionCursor promoted = new ListSuggestionCursorNoDuplicates(mQuery); 310b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert if (promoter == null) { 311b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert return promoted; 3124572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood } 313b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert promoter.pickPromoted(this, maxPromoted, promoted); 314b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert if (DBG) { 315b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert Log.d(TAG, "pickPromoted(" + getShortcuts() + "," + mCorpusResults + "," 316b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert + maxPromoted + ") = " + promoted); 317b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 318b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert return promoted; 3194572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood } 3204572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood 321b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert /** 322b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Gets the list of corpus results reported so far. Do not modify or hang on to 323b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * the returned iterator. 324b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert */ 325b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public Iterable<CorpusResult> getCorpusResults() { 32600efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood ArrayList<CorpusResult> results = new ArrayList<CorpusResult>(mCorpusResults.length); 32700efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood for (int i = 0; i < mCorpusResults.length; ++i) { 32800efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood if (mCorpusResults[i] != null) { 32900efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood results.add(mCorpusResults[i]); 33000efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood } 33100efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood } 33200efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood return results; 333b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 334b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 335b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public CorpusResult getCorpusResult(Corpus corpus) { 336b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert for (CorpusResult result : mCorpusResults) { 337723b496d757c34d8ea745c4f650b353f5791e1ceMathew Inwood if (result != null && corpus.equals(result.getCorpus())) { 338b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert return result; 339b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 340b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 341b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert return null; 342b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 343b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 344b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public CorpusResult getWebResult() { 345b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert return mWebResult; 346b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 34794e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 348b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert /** 349b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Gets the number of source results. 350b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Must be called on the UI thread, or before this object is seen by the UI thread. 351b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert */ 352b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public int getResultCount() { 353b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert if (isClosed()) { 354b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert throw new IllegalStateException("Called getSourceCount() when closed."); 355b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 35600efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood return countCorpusResults(); 357b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 358b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 359b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert @Override 360b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public String toString() { 361b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert return "Suggestions@" + hashCode() + "{expectedCorpora=" + mExpectedCorpora 36200efc7712fd9fce49f1c8e1a4de71784958f8a35Mathew Inwood + ",countCorpusResults()=" + countCorpusResults() + "}"; 363b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 3644572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood 3654572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood private class MyShortcutsObserver extends DataSetObserver { 3664572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood @Override 3674572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood public void onChanged() { 3684572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood notifyDataSetChanged(); 3694572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood } 3704572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood } 3714572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood 3723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert} 373