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.CorpusResult; 20 import com.android.quicksearchbox.Promoter; 21 import com.android.quicksearchbox.SuggestionCursor; 22 import com.android.quicksearchbox.SuggestionPosition; 23 import com.android.quicksearchbox.Suggestions; 24 25 import android.database.DataSetObserver; 26 import android.util.Log; 27 import 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 */ 33 public 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