/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.quicksearchbox.ui import android.database.DataSetObserver import android.util.Log import android.view.View.OnFocusChangeListener import com.android.quicksearchbox.SuggestionCursor import com.android.quicksearchbox.SuggestionPosition import com.android.quicksearchbox.Suggestions /** * A [SuggestionsListAdapter] that doesn't expose the new suggestions until there are some results * to show. */ class DelayingSuggestionsAdapter(private val mDelayedAdapter: SuggestionsAdapterBase) : SuggestionsAdapter { private var mPendingDataSetObserver: DataSetObserver? = null private var mPendingSuggestions: Suggestions? = null fun close() { setPendingSuggestions(null) mDelayedAdapter.close() } /** Gets whether the given suggestions are non-empty for the selected source. */ private fun shouldPublish(suggestions: Suggestions?): Boolean { if (suggestions!!.isDone) return true val cursor: SuggestionCursor? = suggestions.getResult() return cursor != null && cursor.count > 0 } private fun setPendingSuggestions(suggestions: Suggestions?) { if (mPendingSuggestions === suggestions) { return } if (mDelayedAdapter.isClosed) { suggestions?.release() return } if (mPendingDataSetObserver == null) { mPendingDataSetObserver = PendingSuggestionsObserver() } if (mPendingSuggestions != null) { mPendingSuggestions!!.unregisterDataSetObserver(mPendingDataSetObserver) // Close old suggestions, but only if they are not also the current // suggestions. if (mPendingSuggestions !== this.suggestions) { mPendingSuggestions!!.release() } } mPendingSuggestions = suggestions if (mPendingSuggestions != null) { mPendingSuggestions!!.registerDataSetObserver(mPendingDataSetObserver) } } protected fun onPendingSuggestionsChanged() { if (DBG) Log.d(TAG, "onPendingSuggestionsChanged(), mPendingSuggestions=" + mPendingSuggestions) if (shouldPublish(mPendingSuggestions)) { if (DBG) Log.d(TAG, "Suggestions now available, publishing: $mPendingSuggestions") mDelayedAdapter.suggestions = mPendingSuggestions // The suggestions are no longer pending. setPendingSuggestions(null) } } private inner class PendingSuggestionsObserver : DataSetObserver() { @Override override fun onChanged() { onPendingSuggestionsChanged() } } @get:Override override val listAdapter: A get() = mDelayedAdapter.listAdapter val currentPromotedSuggestions: SuggestionCursor? get() = mDelayedAdapter.currentSuggestions // Clear any old pending suggestions. @get:Override @set:Override override var suggestions: Suggestions? get() = mDelayedAdapter.suggestions set(suggestions) { if (suggestions == null) { mDelayedAdapter.suggestions = null setPendingSuggestions(null) return } if (shouldPublish(suggestions)) { if (DBG) Log.d(TAG, "Publishing suggestions immediately: $suggestions") mDelayedAdapter.suggestions = suggestions // Clear any old pending suggestions. setPendingSuggestions(null) } else { if (DBG) Log.d(TAG, "Delaying suggestions publishing: $suggestions") setPendingSuggestions(suggestions) } } @Override override fun getSuggestion(suggestionId: Long): SuggestionPosition? { return mDelayedAdapter.getSuggestion(suggestionId) } @Override override fun onSuggestionClicked(suggestionId: Long) { mDelayedAdapter.onSuggestionClicked(suggestionId) } @Override override fun onSuggestionQueryRefineClicked(suggestionId: Long) { mDelayedAdapter.onSuggestionQueryRefineClicked(suggestionId) } @Override override fun setOnFocusChangeListener(l: OnFocusChangeListener?) { mDelayedAdapter.setOnFocusChangeListener(l) } @Override override fun setSuggestionClickListener(listener: SuggestionClickListener?) { mDelayedAdapter.setSuggestionClickListener(listener) } @get:Override override val isEmpty: Boolean get() = mDelayedAdapter.isEmpty companion object { private const val DBG = false private const val TAG = "QSB.DelayingSuggestionsAdapter" } }