blob: 459723fc40044c6b381a6df143693debc8564bd5 [file] [log] [blame]
Jason Monk8a452e92017-10-31 19:21:47 -04001/*
2 * Copyright 2017 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
17package androidx.app.slice.widget;
18
Jason Monkdcb5e2f2017-11-15 20:19:43 -050019import static android.app.slice.Slice.HINT_HORIZONTAL;
Jason Monk0c76d302017-11-21 14:02:27 -050020import static android.app.slice.Slice.SUBTYPE_MESSAGE;
21import static android.app.slice.Slice.SUBTYPE_SOURCE;
22import static android.app.slice.SliceItem.FORMAT_COLOR;
23import static android.app.slice.SliceItem.FORMAT_IMAGE;
24import static android.app.slice.SliceItem.FORMAT_TEXT;
25
Jason Monk2a7d0fc2017-11-15 10:10:24 -050026import android.annotation.TargetApi;
Mady Mellorc1334182017-11-10 15:50:35 -080027import android.app.slice.Slice;
Jason Monk8a452e92017-10-31 19:21:47 -040028import android.content.Context;
29import android.support.annotation.RestrictTo;
30import android.support.v7.widget.RecyclerView;
31import android.util.ArrayMap;
32import android.view.LayoutInflater;
33import android.view.View;
34import android.view.ViewGroup;
35import android.view.ViewGroup.LayoutParams;
36
37import java.util.ArrayList;
38import java.util.List;
Jason Monk2a7d0fc2017-11-15 10:10:24 -050039import java.util.function.Consumer;
40import java.util.function.Function;
Jason Monk8a452e92017-10-31 19:21:47 -040041import java.util.stream.Collectors;
42
Jason Monkdcb5e2f2017-11-15 20:19:43 -050043import androidx.app.slice.SliceItem;
Jason Monk8a452e92017-10-31 19:21:47 -040044import androidx.app.slice.core.SliceQuery;
45import androidx.app.slice.view.R;
46
47/**
48 * @hide
49 */
50@RestrictTo(RestrictTo.Scope.LIBRARY)
Jason Monk2a7d0fc2017-11-15 10:10:24 -050051@TargetApi(24)
Jason Monk8a452e92017-10-31 19:21:47 -040052public class LargeSliceAdapter extends RecyclerView.Adapter<LargeSliceAdapter.SliceViewHolder> {
53
54 public static final int TYPE_DEFAULT = 1;
Mady Mellorc1334182017-11-10 15:50:35 -080055 public static final int TYPE_HEADER = 2; // TODO headers shouldn't scroll off
Jason Monk8a452e92017-10-31 19:21:47 -040056 public static final int TYPE_GRID = 3;
57 public static final int TYPE_MESSAGE = 4;
58 public static final int TYPE_MESSAGE_LOCAL = 5;
59
60 private final IdGenerator mIdGen = new IdGenerator();
61 private final Context mContext;
62 private List<SliceWrapper> mSlices = new ArrayList<>();
63 private SliceItem mColor;
64
65 public LargeSliceAdapter(Context context) {
66 mContext = context;
67 setHasStableIds(true);
68 }
69
70 /**
71 * Set the {@link SliceItem}'s to be displayed in the adapter and the accent color.
72 */
73 public void setSliceItems(List<SliceItem> slices, SliceItem color) {
74 mColor = color;
75 mIdGen.resetUsage();
Jason Monk2a7d0fc2017-11-15 10:10:24 -050076 mSlices = slices.stream().map(new Function<SliceItem, SliceWrapper>() {
77 @Override
78 public SliceWrapper apply(SliceItem s) {
79 return new SliceWrapper(s, mIdGen);
80 }
81 }).collect(Collectors.<SliceWrapper>toList());
Jason Monk8a452e92017-10-31 19:21:47 -040082 notifyDataSetChanged();
83 }
84
85 @Override
86 public SliceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
87 View v = inflateForType(viewType);
88 v.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
89 return new SliceViewHolder(v);
90 }
91
92 @Override
93 public int getItemViewType(int position) {
94 return mSlices.get(position).mType;
95 }
96
97 @Override
98 public long getItemId(int position) {
99 return mSlices.get(position).mId;
100 }
101
102 @Override
103 public int getItemCount() {
104 return mSlices.size();
105 }
106
107 @Override
108 public void onBindViewHolder(SliceViewHolder holder, int position) {
109 SliceWrapper slice = mSlices.get(position);
110 if (holder.mSliceView != null) {
111 holder.mSliceView.setColor(mColor);
Mady Mellorc1334182017-11-10 15:50:35 -0800112 holder.mSliceView.setSliceItem(slice.mItem, position == 0 /* isHeader */);
Jason Monk8a452e92017-10-31 19:21:47 -0400113 }
114 }
115
116 private View inflateForType(int viewType) {
117 switch (viewType) {
118 case TYPE_GRID:
119 return LayoutInflater.from(mContext).inflate(R.layout.abc_slice_grid, null);
120 case TYPE_MESSAGE:
121 return LayoutInflater.from(mContext).inflate(R.layout.abc_slice_message, null);
122 case TYPE_MESSAGE_LOCAL:
123 return LayoutInflater.from(mContext).inflate(R.layout.abc_slice_message_local,
124 null);
125 }
Mady Mellorc1334182017-11-10 15:50:35 -0800126 return new RowView(mContext);
Jason Monk8a452e92017-10-31 19:21:47 -0400127 }
128
129 protected static class SliceWrapper {
130 private final SliceItem mItem;
131 private final int mType;
132 private final long mId;
133
134 public SliceWrapper(SliceItem item, IdGenerator idGen) {
135 mItem = item;
Jason Monk0c76d302017-11-21 14:02:27 -0500136 mType = getFormat(item);
Jason Monk8a452e92017-10-31 19:21:47 -0400137 mId = idGen.getId(item);
138 }
139
Jason Monk0c76d302017-11-21 14:02:27 -0500140 public static int getFormat(SliceItem item) {
141 if (SUBTYPE_MESSAGE.equals(item.getSubType())) {
Jason Monk8a452e92017-10-31 19:21:47 -0400142 // TODO: Better way to determine me or not? Something more like Messaging style.
Jason Monk0c76d302017-11-21 14:02:27 -0500143 if (SliceQuery.findSubtype(item, null, SUBTYPE_SOURCE) != null) {
Jason Monk8a452e92017-10-31 19:21:47 -0400144 return TYPE_MESSAGE;
145 } else {
146 return TYPE_MESSAGE_LOCAL;
147 }
148 }
Jason Monkdcb5e2f2017-11-15 20:19:43 -0500149 if (item.hasHint(HINT_HORIZONTAL)) {
Jason Monk8a452e92017-10-31 19:21:47 -0400150 return TYPE_GRID;
151 }
Mady Mellorc1334182017-11-10 15:50:35 -0800152 if (!item.hasHint(Slice.HINT_LIST_ITEM)) {
153 return TYPE_HEADER;
154 }
Jason Monk8a452e92017-10-31 19:21:47 -0400155 return TYPE_DEFAULT;
156 }
157 }
158
159 /**
160 * A {@link RecyclerView.ViewHolder} for presenting slices in {@link LargeSliceAdapter}.
161 */
162 public static class SliceViewHolder extends RecyclerView.ViewHolder {
163 public final SliceListView mSliceView;
164
165 public SliceViewHolder(View itemView) {
166 super(itemView);
167 mSliceView = itemView instanceof SliceListView ? (SliceListView) itemView : null;
168 }
169 }
170
171 /**
172 * View slices being displayed in {@link LargeSliceAdapter}.
173 */
174 public interface SliceListView {
175 /**
176 * Set the slice item for this view.
177 */
Mady Mellorc1334182017-11-10 15:50:35 -0800178 void setSliceItem(SliceItem slice, boolean isHeader);
Jason Monk8a452e92017-10-31 19:21:47 -0400179
180 /**
181 * Set the color for the items in this view.
182 */
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500183 void setColor(SliceItem color);
Jason Monk8a452e92017-10-31 19:21:47 -0400184 }
185
186 private static class IdGenerator {
187 private long mNextLong = 0;
188 private final ArrayMap<String, Long> mCurrentIds = new ArrayMap<>();
189 private final ArrayMap<String, Integer> mUsedIds = new ArrayMap<>();
190
191 public long getId(SliceItem item) {
192 String str = genString(item);
193 if (!mCurrentIds.containsKey(str)) {
194 mCurrentIds.put(str, mNextLong++);
195 }
196 long id = mCurrentIds.get(str);
197 int index = mUsedIds.getOrDefault(str, 0);
198 mUsedIds.put(str, index + 1);
199 return id + index * 10000;
200 }
201
202 private String genString(SliceItem item) {
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500203 final StringBuilder builder = new StringBuilder();
204 SliceQuery.stream(item).forEach(new Consumer<SliceItem>() {
205 @Override
206 public void accept(SliceItem i) {
207 builder.append(i.getFormat());
208 //i.removeHint(Slice.HINT_SELECTED);
209 builder.append(i.getHints());
210 switch (i.getFormat()) {
211 case FORMAT_IMAGE:
212 builder.append(i.getIcon());
213 break;
214 case FORMAT_TEXT:
215 builder.append(i.getText());
216 break;
217 case FORMAT_COLOR:
218 builder.append(i.getColor());
219 break;
220 }
Jason Monk8a452e92017-10-31 19:21:47 -0400221 }
222 });
223 return builder.toString();
224 }
225
226 public void resetUsage() {
227 mUsedIds.clear();
228 }
229 }
230}