Add API for setting a fixed list of RemoteViews on an AdapterView
Bug: 182467111 Test: Sample app trying out different combinations of views and event listeners Test: atest RemoteViewsFixedCollectionAdapterTest Change-Id: Ia3fc0af0499cbfaa85e9eb1bf2a24f1e404f17a3
This commit is contained in:
@@ -55028,6 +55028,7 @@ package android.widget {
|
||||
method public void setRelativeScrollPosition(@IdRes int, int);
|
||||
method @Deprecated public void setRemoteAdapter(int, @IdRes int, android.content.Intent);
|
||||
method public void setRemoteAdapter(@IdRes int, android.content.Intent);
|
||||
method public void setRemoteAdapter(@IdRes int, @NonNull android.widget.RemoteViews.RemoteCollectionItems);
|
||||
method public void setScrollPosition(@IdRes int, int);
|
||||
method public void setShort(@IdRes int, String, short);
|
||||
method public void setString(@IdRes int, String, String);
|
||||
@@ -55067,6 +55068,25 @@ package android.widget {
|
||||
ctor public RemoteViews.ActionException(String);
|
||||
}
|
||||
|
||||
public static final class RemoteViews.RemoteCollectionItems implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public int getItemCount();
|
||||
method public long getItemId(int);
|
||||
method @NonNull public android.widget.RemoteViews getItemView(int);
|
||||
method public int getViewTypeCount();
|
||||
method public boolean hasStableIds();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.widget.RemoteViews.RemoteCollectionItems> CREATOR;
|
||||
}
|
||||
|
||||
public static final class RemoteViews.RemoteCollectionItems.Builder {
|
||||
ctor public RemoteViews.RemoteCollectionItems.Builder();
|
||||
method @NonNull public android.widget.RemoteViews.RemoteCollectionItems.Builder addItem(long, @NonNull android.widget.RemoteViews);
|
||||
method @NonNull public android.widget.RemoteViews.RemoteCollectionItems build();
|
||||
method @NonNull public android.widget.RemoteViews.RemoteCollectionItems.Builder setHasStableIds(boolean);
|
||||
method @NonNull public android.widget.RemoteViews.RemoteCollectionItems.Builder setViewTypeCount(int);
|
||||
}
|
||||
|
||||
public static class RemoteViews.RemoteResponse {
|
||||
ctor public RemoteViews.RemoteResponse();
|
||||
method @NonNull public android.widget.RemoteViews.RemoteResponse addSharedElement(@IdRes int, @NonNull String);
|
||||
|
||||
217
core/java/android/widget/RemoteCollectionItemsAdapter.java
Normal file
217
core/java/android/widget/RemoteCollectionItemsAdapter.java
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 android.widget;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.RemoteViews.ColorResources;
|
||||
import android.widget.RemoteViews.InteractionHandler;
|
||||
import android.widget.RemoteViews.RemoteCollectionItems;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* List {@link Adapter} backed by a {@link RemoteCollectionItems}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
class RemoteCollectionItemsAdapter extends BaseAdapter {
|
||||
|
||||
private final int mViewTypeCount;
|
||||
|
||||
private RemoteCollectionItems mItems;
|
||||
private InteractionHandler mInteractionHandler;
|
||||
private ColorResources mColorResources;
|
||||
|
||||
private SparseIntArray mLayoutIdToViewType;
|
||||
|
||||
RemoteCollectionItemsAdapter(
|
||||
@NonNull RemoteCollectionItems items,
|
||||
@NonNull InteractionHandler interactionHandler,
|
||||
@NonNull ColorResources colorResources) {
|
||||
// View type count can never increase after an adapter has been set on a ListView.
|
||||
// Additionally, decreasing it could inhibit view recycling if the count were to back and
|
||||
// forth between 3-2-3-2 for example. Therefore, the view type count, should be fixed for
|
||||
// the lifetime of the adapter.
|
||||
mViewTypeCount = items.getViewTypeCount();
|
||||
|
||||
mItems = items;
|
||||
mInteractionHandler = interactionHandler;
|
||||
mColorResources = colorResources;
|
||||
|
||||
initLayoutIdToViewType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the data for the adapter, allowing recycling of views. Note that if the view type
|
||||
* count has increased, a new adapter should be created and set on the AdapterView instead of
|
||||
* calling this method.
|
||||
*/
|
||||
void setData(
|
||||
@NonNull RemoteCollectionItems items,
|
||||
@NonNull InteractionHandler interactionHandler,
|
||||
@NonNull ColorResources colorResources) {
|
||||
if (mViewTypeCount < items.getViewTypeCount()) {
|
||||
throw new IllegalArgumentException(
|
||||
"RemoteCollectionItemsAdapter cannot increase view type count after creation");
|
||||
}
|
||||
|
||||
mItems = items;
|
||||
mInteractionHandler = interactionHandler;
|
||||
mColorResources = colorResources;
|
||||
|
||||
initLayoutIdToViewType();
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void initLayoutIdToViewType() {
|
||||
SparseIntArray previousLayoutIdToViewType = mLayoutIdToViewType;
|
||||
mLayoutIdToViewType = new SparseIntArray(mViewTypeCount);
|
||||
|
||||
int[] layoutIds = IntStream.range(0, mItems.getItemCount())
|
||||
.map(position -> mItems.getItemView(position).getLayoutId())
|
||||
.distinct()
|
||||
.toArray();
|
||||
if (layoutIds.length > mViewTypeCount) {
|
||||
throw new IllegalArgumentException(
|
||||
"Collection items uses " + layoutIds.length + " distinct layouts, which is "
|
||||
+ "more than view type count of " + mViewTypeCount);
|
||||
}
|
||||
|
||||
// Tracks whether a layout id (by index, not value) has been assigned a view type.
|
||||
boolean[] processedLayoutIdIndices = new boolean[layoutIds.length];
|
||||
// Tracks whether a view type has been assigned to a layout id already.
|
||||
boolean[] assignedViewTypes = new boolean[mViewTypeCount];
|
||||
|
||||
if (previousLayoutIdToViewType != null) {
|
||||
for (int i = 0; i < layoutIds.length; i++) {
|
||||
int layoutId = layoutIds[i];
|
||||
// Copy over any previously used view types for layout ids in the collection to keep
|
||||
// view types stable across data updates.
|
||||
int previousViewType = previousLayoutIdToViewType.get(layoutId, -1);
|
||||
// Skip this layout id if it wasn't assigned to a view type previously.
|
||||
if (previousViewType < 0) continue;
|
||||
|
||||
mLayoutIdToViewType.put(layoutId, previousViewType);
|
||||
processedLayoutIdIndices[i] = true;
|
||||
assignedViewTypes[previousViewType] = true;
|
||||
}
|
||||
}
|
||||
|
||||
int lastViewType = -1;
|
||||
for (int i = 0; i < layoutIds.length; i++) {
|
||||
// If a view type has already been assigned to the layout id, skip it.
|
||||
if (processedLayoutIdIndices[i]) continue;
|
||||
|
||||
int layoutId = layoutIds[i];
|
||||
// If no view type is assigned for the layout id, choose the next possible value that
|
||||
// isn't already assigned to a layout id. There is guaranteed to be some value available
|
||||
// due to the prior validation logic that count(distinct layout ids) <= viewTypeCount.
|
||||
int viewType = IntStream.range(lastViewType + 1, layoutIds.length)
|
||||
.filter(type -> !assignedViewTypes[type])
|
||||
.findFirst()
|
||||
.orElseThrow(
|
||||
() -> new IllegalStateException(
|
||||
"RemoteCollectionItems has more distinct layout ids than its "
|
||||
+ "view type count"));
|
||||
mLayoutIdToViewType.put(layoutId, viewType);
|
||||
processedLayoutIdIndices[i] = true;
|
||||
assignedViewTypes[viewType] = true;
|
||||
lastViewType = viewType;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mItems.getItemCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteViews getItem(int position) {
|
||||
return mItems.getItemView(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return mItems.getItemId(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
return mLayoutIdToViewType.get(mItems.getItemView(position).getLayoutId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewTypeCount() {
|
||||
return mViewTypeCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return mItems.hasStableIds();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
||||
if (position >= getCount()) return null;
|
||||
|
||||
RemoteViews item = mItems.getItemView(position);
|
||||
item.addFlags(RemoteViews.FLAG_WIDGET_IS_COLLECTION_CHILD);
|
||||
View reapplyView = getViewToReapply(convertView, item);
|
||||
|
||||
// Reapply the RemoteViews if we can.
|
||||
if (reapplyView != null) {
|
||||
try {
|
||||
item.reapply(
|
||||
parent.getContext(),
|
||||
reapplyView,
|
||||
mInteractionHandler,
|
||||
null /* size */,
|
||||
mColorResources);
|
||||
return reapplyView;
|
||||
} catch (RuntimeException e) {
|
||||
// We can't reapply for some reason, we'll fallback to an apply and inflate a
|
||||
// new view.
|
||||
}
|
||||
}
|
||||
|
||||
return item.apply(
|
||||
parent.getContext(),
|
||||
parent,
|
||||
mInteractionHandler,
|
||||
null /* size */,
|
||||
mColorResources);
|
||||
}
|
||||
|
||||
/** Returns {@code convertView} if it can be used to reapply {@code item}, or null otherwise. */
|
||||
@Nullable
|
||||
private static View getViewToReapply(@Nullable View convertView, @NonNull RemoteViews item) {
|
||||
if (convertView == null) return null;
|
||||
|
||||
Object layoutIdTag = convertView.getTag(R.id.widget_frame);
|
||||
if (!(layoutIdTag instanceof Integer)) return null;
|
||||
|
||||
return item.getLayoutId() == (Integer) layoutIdTag ? convertView : null;
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import android.annotation.Nullable;
|
||||
import android.annotation.Px;
|
||||
import android.annotation.StringRes;
|
||||
import android.annotation.StyleRes;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityOptions;
|
||||
import android.app.ActivityThread;
|
||||
@@ -74,6 +75,7 @@ import android.util.ArrayMap;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.IntArray;
|
||||
import android.util.Log;
|
||||
import android.util.LongArray;
|
||||
import android.util.Pair;
|
||||
import android.util.SizeF;
|
||||
import android.util.SparseIntArray;
|
||||
@@ -112,6 +114,7 @@ import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -224,6 +227,7 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
private static final int SET_VIEW_OUTLINE_RADIUS_TAG = 28;
|
||||
private static final int SET_ON_CHECKED_CHANGE_RESPONSE_TAG = 29;
|
||||
private static final int NIGHT_MODE_REFLECTION_ACTION_TAG = 30;
|
||||
private static final int SET_REMOTE_COLLECTION_ITEMS_ADAPTER_TAG = 31;
|
||||
|
||||
/** @hide **/
|
||||
@IntDef(prefix = "MARGIN_", value = {
|
||||
@@ -899,6 +903,72 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
ArrayList<RemoteViews> list;
|
||||
}
|
||||
|
||||
private static class SetRemoteCollectionItemListAdapterAction extends Action {
|
||||
private final RemoteCollectionItems mItems;
|
||||
|
||||
SetRemoteCollectionItemListAdapterAction(@IdRes int id, RemoteCollectionItems items) {
|
||||
viewId = id;
|
||||
mItems = items;
|
||||
}
|
||||
|
||||
SetRemoteCollectionItemListAdapterAction(Parcel parcel) {
|
||||
viewId = parcel.readInt();
|
||||
mItems = parcel.readTypedObject(RemoteCollectionItems.CREATOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(viewId);
|
||||
dest.writeTypedObject(mItems, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
|
||||
ColorResources colorResources) throws ActionException {
|
||||
View target = root.findViewById(viewId);
|
||||
if (target == null) return;
|
||||
|
||||
if (!(target instanceof AdapterView)) {
|
||||
Log.e(LOG_TAG, "Cannot call setRemoteAdapter on a view which is not "
|
||||
+ "an AdapterView (id: " + viewId + ")");
|
||||
return;
|
||||
}
|
||||
|
||||
AdapterView adapterView = (AdapterView) target;
|
||||
Adapter adapter = adapterView.getAdapter();
|
||||
// We can reuse the adapter if it's a RemoteCollectionItemsAdapter and the view type
|
||||
// count hasn't increased. Note that AbsListView allocates a fixed size array for view
|
||||
// recycling in setAdapter, so we must call setAdapter again if the number of view types
|
||||
// increases.
|
||||
if (adapter instanceof RemoteCollectionItemsAdapter
|
||||
&& adapter.getViewTypeCount() >= mItems.getViewTypeCount()) {
|
||||
try {
|
||||
((RemoteCollectionItemsAdapter) adapter).setData(
|
||||
mItems, handler, colorResources);
|
||||
} catch (Throwable throwable) {
|
||||
// setData should never failed with the validation in the items builder, but if
|
||||
// it does, catch and rethrow.
|
||||
throw new ActionException(throwable);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
adapterView.setAdapter(
|
||||
new RemoteCollectionItemsAdapter(mItems, handler, colorResources));
|
||||
} catch (Throwable throwable) {
|
||||
// This could throw if the AdapterView somehow doesn't accept BaseAdapter due to
|
||||
// a type error.
|
||||
throw new ActionException(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActionTag() {
|
||||
return SET_REMOTE_COLLECTION_ITEMS_ADAPTER_TAG;
|
||||
}
|
||||
}
|
||||
|
||||
private class SetRemoteViewsAdapterIntent extends Action {
|
||||
public SetRemoteViewsAdapterIntent(@IdRes int id, Intent intent) {
|
||||
this.viewId = id;
|
||||
@@ -3543,6 +3613,8 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
return new SetOnCheckedChangeResponse(parcel);
|
||||
case NIGHT_MODE_REFLECTION_ACTION_TAG:
|
||||
return new NightModeReflectionAction(parcel);
|
||||
case SET_REMOTE_COLLECTION_ITEMS_ADAPTER_TAG:
|
||||
return new SetRemoteCollectionItemListAdapterAction(parcel);
|
||||
default:
|
||||
throw new ActionException("Tag " + tag + " not found");
|
||||
}
|
||||
@@ -4214,6 +4286,25 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
addAction(new SetRemoteViewsAdapterList(viewId, list, viewTypeCount));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a simple Adapter for the viewId specified. The viewId must point to an AdapterView,
|
||||
* ie. {@link ListView}, {@link GridView}, {@link StackView} or {@link AdapterViewAnimator}.
|
||||
* This is a simpler but less flexible approach to populating collection widgets. Its use is
|
||||
* encouraged for most scenarios, as long as the total memory within the list of RemoteViews
|
||||
* is relatively small (ie. doesn't contain large or numerous Bitmaps, see {@link
|
||||
* RemoteViews#setImageViewBitmap}). In the case of numerous images, the use of API is still
|
||||
* possible by setting image URIs instead of Bitmaps, see {@link RemoteViews#setImageViewUri}.
|
||||
*
|
||||
* This API is supported in the compatibility library for previous API levels, see
|
||||
* RemoteViewsCompat.
|
||||
*
|
||||
* @param viewId The id of the {@link AdapterView}.
|
||||
* @param items The items to display in the {@link AdapterView}.
|
||||
*/
|
||||
public void setRemoteAdapter(@IdRes int viewId, @NonNull RemoteCollectionItems items) {
|
||||
addAction(new SetRemoteCollectionItemListAdapterAction(viewId, items));
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to calling {@link ListView#smoothScrollToPosition(int)}.
|
||||
*
|
||||
@@ -6026,6 +6117,203 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Representation of a fixed list of items to be displayed in a RemoteViews collection. */
|
||||
public static final class RemoteCollectionItems implements Parcelable {
|
||||
private final long[] mIds;
|
||||
private final RemoteViews[] mViews;
|
||||
private final boolean mHasStableIds;
|
||||
private final int mViewTypeCount;
|
||||
|
||||
RemoteCollectionItems(
|
||||
long[] ids, RemoteViews[] views, boolean hasStableIds, int viewTypeCount) {
|
||||
mIds = ids;
|
||||
mViews = views;
|
||||
mHasStableIds = hasStableIds;
|
||||
mViewTypeCount = viewTypeCount;
|
||||
if (ids.length != views.length) {
|
||||
throw new IllegalArgumentException(
|
||||
"RemoteCollectionItems has different number of ids and views");
|
||||
}
|
||||
if (viewTypeCount < 1) {
|
||||
throw new IllegalArgumentException("View type count must be >= 1");
|
||||
}
|
||||
int layoutIdCount = (int) Arrays.stream(views)
|
||||
.mapToInt(RemoteViews::getLayoutId)
|
||||
.distinct()
|
||||
.count();
|
||||
if (layoutIdCount > viewTypeCount) {
|
||||
throw new IllegalArgumentException(
|
||||
"View type count is set to " + viewTypeCount + ", but the collection "
|
||||
+ "contains " + layoutIdCount + " different layout ids");
|
||||
}
|
||||
}
|
||||
|
||||
RemoteCollectionItems(Parcel in) {
|
||||
int length = in.readInt();
|
||||
mIds = new long[length];
|
||||
in.readLongArray(mIds);
|
||||
mViews = new RemoteViews[length];
|
||||
in.readTypedArray(mViews, RemoteViews.CREATOR);
|
||||
mHasStableIds = in.readBoolean();
|
||||
mViewTypeCount = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeInt(mIds.length);
|
||||
dest.writeLongArray(mIds);
|
||||
dest.writeTypedArray(mViews, flags);
|
||||
dest.writeBoolean(mHasStableIds);
|
||||
dest.writeInt(mViewTypeCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id for {@code position}. See {@link #hasStableIds()} for whether this id
|
||||
* should be considered meaningful across collection updates.
|
||||
*
|
||||
* @return Id for the position.
|
||||
*/
|
||||
public long getItemId(int position) {
|
||||
return mIds[position];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link RemoteViews} to display at {@code position}.
|
||||
*
|
||||
* @return RemoteViews for the position.
|
||||
*/
|
||||
@NonNull
|
||||
public RemoteViews getItemView(int position) {
|
||||
return mViews[position];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements in the collection.
|
||||
*
|
||||
* @return Count of items.
|
||||
*/
|
||||
public int getItemCount() {
|
||||
return mIds.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public int getViewTypeCount() {
|
||||
return mViewTypeCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public boolean hasStableIds() {
|
||||
return mHasStableIds;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<RemoteCollectionItems> CREATOR =
|
||||
new Creator<RemoteCollectionItems>() {
|
||||
@NonNull
|
||||
@Override
|
||||
public RemoteCollectionItems createFromParcel(@NonNull Parcel source) {
|
||||
return new RemoteCollectionItems(source);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RemoteCollectionItems[] newArray(int size) {
|
||||
return new RemoteCollectionItems[size];
|
||||
}
|
||||
};
|
||||
|
||||
/** Builder class for {@link RemoteCollectionItems} objects.*/
|
||||
public static final class Builder {
|
||||
private final LongArray mIds = new LongArray();
|
||||
private final List<RemoteViews> mViews = new ArrayList<>();
|
||||
private boolean mHasStableIds;
|
||||
private int mViewTypeCount;
|
||||
|
||||
/**
|
||||
* Adds a {@link RemoteViews} to the collection.
|
||||
*
|
||||
* @param id Id to associate with the row. Use {@link #setHasStableIds(boolean)} to
|
||||
* indicate that ids are stable across changes to the collection.
|
||||
* @param view RemoteViews to display for the row.
|
||||
*/
|
||||
@NonNull
|
||||
// Covered by getItemId, getItemView, getItemCount.
|
||||
@SuppressLint("MissingGetterMatchingBuilder")
|
||||
public Builder addItem(long id, @NonNull RemoteViews view) {
|
||||
if (view == null) throw new NullPointerException();
|
||||
if (view.hasMultipleLayouts()) {
|
||||
throw new IllegalArgumentException(
|
||||
"RemoteViews used in a RemoteCollectionItems cannot specify separate "
|
||||
+ "layouts for orientations or sizes.");
|
||||
}
|
||||
mIds.add(id);
|
||||
mViews.add(view);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the item ids are stable across changes to the underlying data.
|
||||
*
|
||||
* @see android.widget.Adapter#hasStableIds()
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setHasStableIds(boolean hasStableIds) {
|
||||
mHasStableIds = 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()
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setViewTypeCount(int viewTypeCount) {
|
||||
mViewTypeCount = viewTypeCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Creates the {@link RemoteCollectionItems} defined by this builder. */
|
||||
@NonNull
|
||||
public RemoteCollectionItems build() {
|
||||
if (mViewTypeCount < 1) {
|
||||
// If a view type count wasn't specified, set it to be the number of distinct
|
||||
// layout ids used in the items.
|
||||
mViewTypeCount = (int) mViews.stream()
|
||||
.mapToInt(RemoteViews::getLayoutId)
|
||||
.distinct()
|
||||
.count();
|
||||
}
|
||||
return new RemoteCollectionItems(
|
||||
mIds.toArray(),
|
||||
mViews.toArray(new RemoteViews[0]),
|
||||
mHasStableIds,
|
||||
Math.max(mViewTypeCount, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ID of the top-level view of the XML layout.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user