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