1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.quicksearchbox;
18 
19 import android.database.DataSetObservable;
20 import android.database.DataSetObserver;
21 import android.util.Log;
22 
23 /**
24  * Collects all corpus results for a single query.
25  */
26 public class Suggestions {
27     private static final boolean DBG = false;
28     private static final String TAG = "QSB.Suggestions";
29 
30     /** True if {@link Suggestions#close} has been called. */
31     private boolean mClosed = false;
32     protected final String mQuery;
33 
34     /**
35      * The observers that want notifications of changes to the published suggestions.
36      * This object may be accessed on any thread.
37      */
38     private final DataSetObservable mDataSetObservable = new DataSetObservable();
39 
40     private Source mSource;
41 
42     private SourceResult mResult;
43 
44     private int mRefCount = 0;
45 
46     private boolean mDone = false;
47 
Suggestions(String query, Source source)48     public Suggestions(String query, Source source) {
49         mQuery = query;
50         mSource = source;
51     }
52 
acquire()53     public void acquire() {
54         mRefCount++;
55     }
56 
release()57     public void release() {
58         mRefCount--;
59         if (mRefCount <= 0) {
60             close();
61         }
62     }
63 
getSource()64     public Source getSource() {
65         return mSource;
66     }
67 
68     /**
69      * Marks the suggestions set as complete, regardless of whether all corpora have
70      * returned.
71      */
done()72     public void done() {
73         mDone = true;
74     }
75 
76     /**
77      * Checks whether all sources have reported.
78      * Must be called on the UI thread, or before this object is seen by the UI thread.
79      */
isDone()80     public boolean isDone() {
81         return mDone || mResult != null;
82     }
83 
84     /**
85      * Adds a list of corpus results. Must be called on the UI thread, or before this
86      * object is seen by the UI thread.
87      */
addResults(SourceResult result)88     public void addResults(SourceResult result) {
89         if (isClosed()) {
90             result.close();
91             return;
92         }
93 
94         if (DBG) {
95             Log.d(TAG, "addResults["+ hashCode() + "] source:" +
96                     result.getSource().getName() + " results:" + result.getCount());
97         }
98         if (!mQuery.equals(result.getUserQuery())) {
99           throw new IllegalArgumentException("Got result for wrong query: "
100                 + mQuery + " != " + result.getUserQuery());
101         }
102         mResult = result;
103         notifyDataSetChanged();
104     }
105 
106     /**
107      * Registers an observer that will be notified when the reported results or
108      * the done status changes.
109      */
registerDataSetObserver(DataSetObserver observer)110     public void registerDataSetObserver(DataSetObserver observer) {
111         if (mClosed) {
112             throw new IllegalStateException("registerDataSetObserver() when closed");
113         }
114         mDataSetObservable.registerObserver(observer);
115     }
116 
117 
118     /**
119      * Unregisters an observer.
120      */
unregisterDataSetObserver(DataSetObserver observer)121     public void unregisterDataSetObserver(DataSetObserver observer) {
122         mDataSetObservable.unregisterObserver(observer);
123     }
124 
125     /**
126      * Calls {@link DataSetObserver#onChanged()} on all observers.
127      */
notifyDataSetChanged()128     protected void notifyDataSetChanged() {
129         if (DBG) Log.d(TAG, "notifyDataSetChanged()");
130         mDataSetObservable.notifyChanged();
131     }
132 
133     /**
134      * Closes all the source results and unregisters all observers.
135      */
close()136     private void close() {
137         if (DBG) Log.d(TAG, "close() [" + hashCode() + "]");
138         if (mClosed) {
139             throw new IllegalStateException("Double close()");
140         }
141         mClosed = true;
142         mDataSetObservable.unregisterAll();
143         if (mResult != null) {
144             mResult.close();
145         }
146         mResult = null;
147     }
148 
isClosed()149     public boolean isClosed() {
150         return mClosed;
151     }
152 
153     @Override
finalize()154     protected void finalize() {
155         if (!mClosed) {
156             Log.e(TAG, "LEAK! Finalized without being closed: Suggestions[" + getQuery() + "]");
157         }
158     }
159 
getQuery()160     public String getQuery() {
161         return mQuery;
162     }
163 
164     /**
165      * Gets the list of corpus results reported so far. Do not modify or hang on to
166      * the returned iterator.
167      */
getResult()168     public SourceResult getResult() {
169         return mResult;
170     }
171 
getWebResult()172     public SourceResult getWebResult() {
173         return mResult;
174     }
175 
176     /**
177      * Gets the number of source results.
178      * Must be called on the UI thread, or before this object is seen by the UI thread.
179      */
getResultCount()180     public int getResultCount() {
181         if (isClosed()) {
182             throw new IllegalStateException("Called getSourceCount() when closed.");
183         }
184         return mResult == null ? 0 : mResult.getCount();
185     }
186 
187     @Override
toString()188     public String toString() {
189         return "Suggestions@" + hashCode() + "{source=" + mSource
190                 + ",getResultCount()=" + getResultCount() + "}";
191     }
192 
193 }
194