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.SuggestionCursor;
20import com.android.quicksearchbox.SuggestionPosition;
21import com.android.quicksearchbox.Suggestions;
22
23import android.database.DataSetObserver;
24import android.util.Log;
25import 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 */
31public 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
42    public DelayingSuggestionsAdapter(SuggestionsAdapterBase<A> delayed) {
43        mDelayedAdapter = delayed;
44    }
45
46    public void close() {
47        setPendingSuggestions(null);
48        mDelayedAdapter.close();
49    }
50
51    @Override
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     */
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
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
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
123        public void onChanged() {
124            onPendingSuggestionsChanged();
125        }
126    }
127
128    @Override
129    public A getListAdapter() {
130        return mDelayedAdapter.getListAdapter();
131    }
132
133    public SuggestionCursor getCurrentPromotedSuggestions() {
134        return mDelayedAdapter.getCurrentSuggestions();
135    }
136
137    @Override
138    public Suggestions getSuggestions() {
139        return mDelayedAdapter.getSuggestions();
140    }
141
142    @Override
143    public SuggestionPosition getSuggestion(long suggestionId) {
144        return mDelayedAdapter.getSuggestion(suggestionId);
145    }
146
147    @Override
148    public void onSuggestionClicked(long suggestionId) {
149        mDelayedAdapter.onSuggestionClicked(suggestionId);
150    }
151
152    @Override
153    public void onSuggestionQueryRefineClicked(long suggestionId) {
154        mDelayedAdapter.onSuggestionQueryRefineClicked(suggestionId);
155    }
156
157    @Override
158    public void setOnFocusChangeListener(OnFocusChangeListener l) {
159        mDelayedAdapter.setOnFocusChangeListener(l);
160    }
161
162    @Override
163    public void setSuggestionClickListener(SuggestionClickListener listener) {
164        mDelayedAdapter.setSuggestionClickListener(listener);
165    }
166
167    @Override
168    public boolean isEmpty() {
169        return mDelayedAdapter.isEmpty();
170    }
171
172}
173