RemoteCollectionItems.kt
/*
* Copyright 2023 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 androidx.glance.appwidget
import android.annotation.SuppressLint
import android.widget.RemoteViews
/** Representation of a fixed list of items to be displayed in a RemoteViews collection. */
internal class RemoteCollectionItems private constructor(
private val ids: LongArray,
private val views: Array<RemoteViews>,
private val hasStableIds: Boolean,
private val _viewTypeCount: Int
) {
init {
require(ids.size == views.size) {
"RemoteCollectionItems has different number of ids and views"
}
require(_viewTypeCount >= 1) { "View type count must be >= 1" }
val layoutIdCount = views.map { it.layoutId }.distinct().count()
require(layoutIdCount <= _viewTypeCount) {
"View type count is set to $_viewTypeCount, but the collection contains " +
"$layoutIdCount different layout ids"
}
}
/**
* Returns the id for [position]. See [hasStableIds] for whether this id should be
* considered meaningful across collection updates.
*
* @return Id for the position.
*/
fun getItemId(position: Int): Long = ids[position]
/**
* Returns the [RemoteViews] to display at [position].
*
* @return RemoteViews for the position.
*/
fun getItemView(position: Int): RemoteViews = views[position]
/**
* Returns the number of elements in the collection.
*
* @return Count of items.
*/
val itemCount: Int
get() = ids.size
/**
* Returns the view type count for the collection when used in an adapter
*
* @return Count of view types for the collection when used in an adapter.
* @see android.widget.Adapter.getViewTypeCount
*/
val viewTypeCount: Int
get() = _viewTypeCount
/**
* Indicates whether the item ids are stable across changes to the underlying data.
*
* @return True if the same id always refers to the same object.
* @see android.widget.Adapter.hasStableIds
*/
fun hasStableIds(): Boolean = hasStableIds
/** Builder class for [RemoteCollectionItems] objects. */
class Builder {
private val ids = arrayListOf<Long>()
private val views = arrayListOf<RemoteViews>()
private var hasStableIds = false
private var viewTypeCount = 0
/**
* Adds a [RemoteViews] to the collection.
*
* @param id Id to associate with the row. Use [.setHasStableIds] to indicate that ids are
* stable across changes to the collection.
* @param view RemoteViews to display for the row.
*/
// Covered by getItemId, getItemView, getItemCount.
@SuppressLint("MissingGetterMatchingBuilder")
fun addItem(id: Long, view: RemoteViews): Builder {
ids.add(id)
views.add(view)
return this
}
/**
* Sets whether the item ids are stable across changes to the underlying data.
*
* @see android.widget.Adapter.hasStableIds
*/
fun setHasStableIds(hasStableIds: Boolean): Builder {
this.hasStableIds = hasStableIds
return this
}
/**
* Sets the view type count for the collection when used in an adapter. This can be set
* to the maximum number of different layout ids that will be used by RemoteViews in
* this collection.
*
* If this value is not set, then a value will be inferred from the provided items. As
* a result, the adapter may need to be recreated when the list is updated with
* previously unseen RemoteViews layouts for new items.
*
* @see android.widget.Adapter.getViewTypeCount
*/
fun setViewTypeCount(viewTypeCount: Int): Builder {
this.viewTypeCount = viewTypeCount
return this
}
/** Creates the [RemoteCollectionItems] defined by this builder. */
fun build(): RemoteCollectionItems {
if (viewTypeCount < 1) {
// If a view type count wasn't specified, set it to be the number of distinct
// layout ids used in the items.
viewTypeCount = views.map { it.layoutId }.distinct().count()
}
return RemoteCollectionItems(
ids.toLongArray(),
views.toTypedArray(),
hasStableIds,
maxOf(viewTypeCount, 1)
)
}
}
companion object {
val Empty = RemoteCollectionItems(
ids = longArrayOf(),
views = emptyArray(),
hasStableIds = false,
_viewTypeCount = 1
)
}
}