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 193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.database.DataSetObservable; 203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.database.DataSetObserver; 213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.util.Log; 223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 23b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert/** 24b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Collects all corpus results for a single query. 25b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert */ 26b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringertpublic class Suggestions { 27cef2c4c9d54f513babd74801dbed5cbf709b9b79Bjorn Bringert private static final boolean DBG = false; 283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private static final String TAG = "QSB.Suggestions"; 293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 30848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani /** True if {@link Suggestions#close} has been called. */ 31848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani private boolean mClosed = false; 32848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani protected final String mQuery; 333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * The observers that want notifications of changes to the published suggestions. 363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * This object may be accessed on any thread. 373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final DataSetObservable mDataSetObservable = new DataSetObservable(); 393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 40ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood private Source mSource; 41b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 42ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood private SourceResult mResult; 43b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 44b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert private int mRefCount = 0; 45b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 463540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert private boolean mDone = false; 473540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert 48ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood public Suggestions(String query, Source source) { 493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mQuery = query; 50ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood mSource = source; 51b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 52b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 53b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public void acquire() { 54b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert mRefCount++; 55b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 56b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 57b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public void release() { 58b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert mRefCount--; 59b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert if (mRefCount <= 0) { 60b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert close(); 61b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 62b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 63b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 64ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood public Source getSource() { 65ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood return mSource; 663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 693540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert * Marks the suggestions set as complete, regardless of whether all corpora have 703540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert * returned. 713540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert */ 723540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert public void done() { 733540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert mDone = true; 743540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert } 753540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert 763540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert /** 77b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Checks whether all sources have reported. 78b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Must be called on the UI thread, or before this object is seen by the UI thread. 79b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert */ 80b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public boolean isDone() { 81ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood return mDone || mResult != null; 82b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 83b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 84b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert /** 85b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Adds a list of corpus results. Must be called on the UI thread, or before this 86b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * object is seen by the UI thread. 87b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert */ 88ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood public void addResults(SourceResult result) { 89b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert if (isClosed()) { 90ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood result.close(); 91b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert return; 92b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 93b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 94ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood if (DBG) { 95ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood Log.d(TAG, "addResults["+ hashCode() + "] source:" + 96ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood result.getSource().getName() + " results:" + result.getCount()); 97ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood } 98ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood if (!mQuery.equals(result.getUserQuery())) { 99ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood throw new IllegalArgumentException("Got result for wrong query: " 100ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood + mQuery + " != " + result.getUserQuery()); 101b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 102ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood mResult = result; 103b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert notifyDataSetChanged(); 104b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 105b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 106b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert /** 1073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Registers an observer that will be notified when the reported results or 1083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * the done status changes. 1093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 1103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void registerDataSetObserver(DataSetObserver observer) { 1113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mClosed) { 1123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert throw new IllegalStateException("registerDataSetObserver() when closed"); 1133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mDataSetObservable.registerObserver(observer); 1153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 117848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani 1183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 1193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Unregisters an observer. 1203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 1213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void unregisterDataSetObserver(DataSetObserver observer) { 1223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mDataSetObservable.unregisterObserver(observer); 1233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 125e06b7cbf55301a24cfd7525a91107e3cd2c9f48eBjorn Bringert /** 1263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Calls {@link DataSetObserver#onChanged()} on all observers. 1273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 128848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani protected void notifyDataSetChanged() { 1293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "notifyDataSetChanged()"); 1303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mDataSetObservable.notifyChanged(); 1313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 133b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert /** 134b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Closes all the source results and unregisters all observers. 135b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert */ 136b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert private void close() { 137b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert if (DBG) Log.d(TAG, "close() [" + hashCode() + "]"); 1383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mClosed) { 139185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert throw new IllegalStateException("Double close()"); 1403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mClosed = true; 142848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani mDataSetObservable.unregisterAll(); 143ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood if (mResult != null) { 144ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood mResult.close(); 1454572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood } 146ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood mResult = null; 1473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 14927d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney public boolean isClosed() { 15027d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney return mClosed; 15127d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney } 15227d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney 1533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 1543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void finalize() { 1553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (!mClosed) { 156848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani Log.e(TAG, "LEAK! Finalized without being closed: Suggestions[" + getQuery() + "]"); 1573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 160848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani public String getQuery() { 161848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani return mQuery; 162ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert } 163ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert 164b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert /** 165b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Gets the list of corpus results reported so far. Do not modify or hang on to 166b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * the returned iterator. 167b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert */ 168ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood public SourceResult getResult() { 169ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood return mResult; 170b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 171b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 172ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood public SourceResult getWebResult() { 173ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood return mResult; 174b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 17594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 176b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert /** 177b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Gets the number of source results. 178b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert * Must be called on the UI thread, or before this object is seen by the UI thread. 179b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert */ 180b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public int getResultCount() { 181b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert if (isClosed()) { 182b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert throw new IllegalStateException("Called getSourceCount() when closed."); 183b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 184ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood return mResult == null ? 0 : mResult.getCount(); 185b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert } 186b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert 187b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert @Override 188b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert public String toString() { 189ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood return "Suggestions@" + hashCode() + "{source=" + mSource 190ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood + ",getResultCount()=" + getResultCount() + "}"; 1914572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood } 1924572856ac85bb53ea06e65d00beebdf336af9b27Mathew Inwood 1933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert} 194