1 /*
2  * Copyright (C) 2009 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.ui;
18 
19 import com.android.quicksearchbox.SuggestionCursor;
20 import com.android.quicksearchbox.SuggestionPosition;
21 import com.android.quicksearchbox.Suggestions;
22 
23 import android.database.DataSetObserver;
24 import android.util.Log;
25 import android.view.View.OnFocusChangeListener;
26 
27 /**
28  * A {@link SuggestionsListAdapter} that doesn't expose the new suggestions
29  * until there are some results to show.
30  */
31 public class DelayingSuggestionsAdapter<A> implements SuggestionsAdapter<A> {
32 
33     private static final boolean DBG = false;
34     private static final String TAG = "QSB.DelayingSuggestionsAdapter";
35 
36     private DataSetObserver mPendingDataSetObserver;
37 
38     private Suggestions mPendingSuggestions;
39 
40     private final SuggestionsAdapterBase<A> mDelayedAdapter;
41 
DelayingSuggestionsAdapter(SuggestionsAdapterBase<A> delayed)42     public DelayingSuggestionsAdapter(SuggestionsAdapterBase<A> delayed) {
43         mDelayedAdapter = delayed;
44     }
45 
close()46     public void close() {
47         setPendingSuggestions(null);
48         mDelayedAdapter.close();
49     }
50 
51     @Override
setSuggestions(Suggestions suggestions)52     public void setSuggestions(Suggestions suggestions) {
53         if (suggestions == null) {
54             mDelayedAdapter.setSuggestions(null);
55             setPendingSuggestions(null);
56             return;
57         }
58         if (shouldPublish(suggestions)) {
59             if (DBG) Log.d(TAG, "Publishing suggestions immediately: " + suggestions);
60             mDelayedAdapter.setSuggestions(suggestions);
61             // Clear any old pending suggestions.
62             setPendingSuggestions(null);
63         } else {
64             if (DBG) Log.d(TAG, "Delaying suggestions publishing: " + suggestions);
65             setPendingSuggestions(suggestions);
66         }
67     }
68 
69     /**
70      * Gets whether the given suggestions are non-empty for the selected source.
71      */
shouldPublish(Suggestions suggestions)72     private boolean shouldPublish(Suggestions suggestions) {
73         if (suggestions.isDone()) return true;
74         SuggestionCursor cursor = suggestions.getResult();
75         if (cursor != null && cursor.getCount() > 0) {
76             return true;
77         }
78         return false;
79     }
80 
setPendingSuggestions(Suggestions suggestions)81     private void setPendingSuggestions(Suggestions suggestions) {
82         if (mPendingSuggestions == suggestions) {
83             return;
84         }
85         if (mDelayedAdapter.isClosed()) {
86             if (suggestions != null) {
87                 suggestions.release();
88             }
89             return;
90         }
91         if (mPendingDataSetObserver == null) {
92             mPendingDataSetObserver = new PendingSuggestionsObserver();
93         }
94         if (mPendingSuggestions != null) {
95             mPendingSuggestions.unregisterDataSetObserver(mPendingDataSetObserver);
96             // Close old suggestions, but only if they are not also the current
97             // suggestions.
98             if (mPendingSuggestions != getSuggestions()) {
99                 mPendingSuggestions.release();
100             }
101         }
102         mPendingSuggestions = suggestions;
103         if (mPendingSuggestions != null) {
104             mPendingSuggestions.registerDataSetObserver(mPendingDataSetObserver);
105         }
106     }
107 
onPendingSuggestionsChanged()108     protected void onPendingSuggestionsChanged() {
109         if (DBG) {
110             Log.d(TAG, "onPendingSuggestionsChanged(), mPendingSuggestions="
111                     + mPendingSuggestions);
112         }
113         if (shouldPublish(mPendingSuggestions)) {
114             if (DBG) Log.d(TAG, "Suggestions now available, publishing: " + mPendingSuggestions);
115             mDelayedAdapter.setSuggestions(mPendingSuggestions);
116             // The suggestions are no longer pending.
117             setPendingSuggestions(null);
118         }
119     }
120 
121     private class PendingSuggestionsObserver extends DataSetObserver {
122         @Override
onChanged()123         public void onChanged() {
124             onPendingSuggestionsChanged();
125         }
126     }
127 
128     @Override
getListAdapter()129     public A getListAdapter() {
130         return mDelayedAdapter.getListAdapter();
131     }
132 
getCurrentPromotedSuggestions()133     public SuggestionCursor getCurrentPromotedSuggestions() {
134         return mDelayedAdapter.getCurrentSuggestions();
135     }
136 
137     @Override
getSuggestions()138     public Suggestions getSuggestions() {
139         return mDelayedAdapter.getSuggestions();
140     }
141 
142     @Override
getSuggestion(long suggestionId)143     public SuggestionPosition getSuggestion(long suggestionId) {
144         return mDelayedAdapter.getSuggestion(suggestionId);
145     }
146 
147     @Override
onSuggestionClicked(long suggestionId)148     public void onSuggestionClicked(long suggestionId) {
149         mDelayedAdapter.onSuggestionClicked(suggestionId);
150     }
151 
152     @Override
onSuggestionQueryRefineClicked(long suggestionId)153     public void onSuggestionQueryRefineClicked(long suggestionId) {
154         mDelayedAdapter.onSuggestionQueryRefineClicked(suggestionId);
155     }
156 
157     @Override
setOnFocusChangeListener(OnFocusChangeListener l)158     public void setOnFocusChangeListener(OnFocusChangeListener l) {
159         mDelayedAdapter.setOnFocusChangeListener(l);
160     }
161 
162     @Override
setSuggestionClickListener(SuggestionClickListener listener)163     public void setSuggestionClickListener(SuggestionClickListener listener) {
164         mDelayedAdapter.setSuggestionClickListener(listener);
165     }
166 
167     @Override
isEmpty()168     public boolean isEmpty() {
169         return mDelayedAdapter.isEmpty();
170     }
171 
172 }
173