blob: 83f12a9ab2539592d0127da41ed93d41d2393d43 [file] [log] [blame]
/*
* 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
import android.database.DataSetObservable
import android.database.DataSetObserver
import com.google.common.annotations.VisibleForTesting
import kotlin.collections.ArrayList
import kotlin.collections.HashSet
/** A SuggestionCursor that is backed by a list of Suggestions. */
open class ListSuggestionCursor(userQuery: String?, capacity: Int) :
AbstractSuggestionCursorWrapper(userQuery!!) {
private val mDataSetObservable: DataSetObservable = DataSetObservable()
private val mSuggestions: ArrayList<Entry>
private var mExtraColumns: HashSet<String>? = null
override var position = 0
constructor(userQuery: String?) : this(userQuery, DEFAULT_CAPACITY)
@VisibleForTesting
constructor(
userQuery: String?,
vararg suggestions: Suggestion?
) : this(userQuery, suggestions.size) {
for (suggestion in suggestions) {
add(suggestion!!)
}
}
/**
* Adds a suggestion from another suggestion cursor.
*
* @return `true` if the suggestion was added.
*/
open fun add(suggestion: Suggestion): Boolean {
mSuggestions.add(Entry(suggestion))
return true
}
override fun close() {
mSuggestions.clear()
}
override fun moveTo(pos: Int) {
position = pos
}
override fun moveToNext(): Boolean {
val size: Int = mSuggestions.size
if (position >= size) {
// Already past the end
return false
}
position++
return position < size
}
fun removeRow() {
mSuggestions.removeAt(position)
}
fun replaceRow(suggestion: Suggestion) {
mSuggestions.set(position, Entry(suggestion))
}
override val count: Int
get() = mSuggestions.size
@Override
override fun current(): Suggestion {
return mSuggestions.get(position).get()
}
@Override
override fun toString(): String {
return this::class.simpleName.toString() + "{[" + userQuery + "] " + mSuggestions + "}"
}
/**
* Register an observer that is called when changes happen to this data set.
*
* @param observer gets notified when the data set changes.
*/
override fun registerDataSetObserver(observer: DataSetObserver?) {
mDataSetObservable.registerObserver(observer)
}
/**
* Unregister an observer that has previously been registered with [.registerDataSetObserver]
*
* @param observer the observer to unregister.
*/
override fun unregisterDataSetObserver(observer: DataSetObserver?) {
mDataSetObservable.unregisterObserver(observer)
}
protected fun notifyDataSetChanged() {
mDataSetObservable.notifyChanged()
}
// override with caching to avoid re-parsing the extras
@get:Override
override val extras: SuggestionExtras?
// override with caching to avoid re-parsing the extras
get() = mSuggestions.get(position).getExtras()
override val extraColumns: Collection<String>?
get() {
if (mExtraColumns == null) {
mExtraColumns = HashSet<String>()
for (e in mSuggestions) {
val extras: SuggestionExtras? = e.getExtras()
val extraColumns: Collection<String>? =
if (extras == null) null else extras.extraColumnNames
if (extraColumns != null) {
for (column in extras!!.extraColumnNames) {
mExtraColumns?.add(column)
}
}
}
}
return if (mExtraColumns!!.isEmpty()) null else mExtraColumns
}
/** This class exists purely to cache the suggestion extras. */
private class Entry(private val mSuggestion: Suggestion) {
private var mExtras: SuggestionExtras? = null
fun get(): Suggestion {
return mSuggestion
}
fun getExtras(): SuggestionExtras? {
if (mExtras == null) {
mExtras = mSuggestion.extras
}
return mExtras
}
}
companion object {
private const val DEFAULT_CAPACITY = 16
}
init {
mSuggestions = ArrayList<Entry>(capacity)
}
}