blob: c516021a1ed2c85ed1c10516c6ac07acc53fb219 [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_LIST;
20import static android.app.slice.Slice.HINT_LIST_ITEM;
21import static android.app.slice.Slice.HINT_NO_TINT;
22import static android.app.slice.Slice.HINT_SELECTED;
23import static android.app.slice.Slice.HINT_TITLE;
Jason Monk0c76d302017-11-21 14:02:27 -050024import static android.app.slice.SliceItem.FORMAT_ACTION;
25import static android.app.slice.SliceItem.FORMAT_COLOR;
26import static android.app.slice.SliceItem.FORMAT_IMAGE;
27import static android.app.slice.SliceItem.FORMAT_SLICE;
28import static android.app.slice.SliceItem.FORMAT_TEXT;
29import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
30
Mady Mellorc1334182017-11-10 15:50:35 -080031import static androidx.app.slice.core.SliceHints.EXTRA_TOGGLE_STATE;
Mady Mellor71ef84d2017-12-11 13:33:36 -080032import static androidx.app.slice.core.SliceHints.HINT_SUMMARY;
Mady Mellorc1334182017-11-10 15:50:35 -080033
Jason Monk2a7d0fc2017-11-15 10:10:24 -050034import android.annotation.TargetApi;
Mady Mellordb8aa8c2017-11-08 14:26:17 -080035import android.app.PendingIntent;
Jason Monk8a452e92017-10-31 19:21:47 -040036import android.app.PendingIntent.CanceledException;
Jason Monk8a452e92017-10-31 19:21:47 -040037import android.content.Context;
Mady Mellordb8aa8c2017-11-08 14:26:17 -080038import android.content.Intent;
Mady Mellorc1334182017-11-10 15:50:35 -080039import android.graphics.drawable.Icon;
Jason Monk8a452e92017-10-31 19:21:47 -040040import android.os.AsyncTask;
41import android.support.annotation.RestrictTo;
Mady Mellordb8aa8c2017-11-08 14:26:17 -080042import android.util.Log;
Jason Monk8a452e92017-10-31 19:21:47 -040043import android.view.View;
Jason Monk2a7d0fc2017-11-15 10:10:24 -050044import android.widget.CompoundButton;
Mady Mellor5b2c0ce2017-12-08 12:16:37 -080045import android.widget.FrameLayout;
Jason Monk8a452e92017-10-31 19:21:47 -040046import android.widget.ImageView;
47import android.widget.LinearLayout;
Mady Mellordb8aa8c2017-11-08 14:26:17 -080048import android.widget.Switch;
Jason Monk8a452e92017-10-31 19:21:47 -040049import android.widget.TextView;
Mady Mellorc1334182017-11-10 15:50:35 -080050import android.widget.ToggleButton;
Jason Monk8a452e92017-10-31 19:21:47 -040051
Jason Monk8a452e92017-10-31 19:21:47 -040052import java.util.ArrayList;
Jason Monk8a452e92017-10-31 19:21:47 -040053import java.util.List;
Jason Monk2a7d0fc2017-11-15 10:10:24 -050054import java.util.function.Predicate;
Jason Monk8a452e92017-10-31 19:21:47 -040055
Jason Monkdcb5e2f2017-11-15 20:19:43 -050056import androidx.app.slice.Slice;
57import androidx.app.slice.SliceItem;
Jason Monk8b099f22017-11-15 15:15:48 -050058import androidx.app.slice.core.SliceHints;
Jason Monk8a452e92017-10-31 19:21:47 -040059import androidx.app.slice.core.SliceQuery;
60import androidx.app.slice.view.R;
61
62/**
Mady Mellorc1334182017-11-10 15:50:35 -080063 * Row item is in small template format and can be used to construct list items for use
64 * with {@link LargeTemplateView}.
Jason Monk8a452e92017-10-31 19:21:47 -040065 *
66 * @hide
67 */
68@RestrictTo(RestrictTo.Scope.LIBRARY)
Jason Monk2a7d0fc2017-11-15 10:10:24 -050069@TargetApi(23)
Mady Mellor5b2c0ce2017-12-08 12:16:37 -080070public class RowView extends FrameLayout implements SliceView.SliceModeView,
Mady Mellordb8aa8c2017-11-08 14:26:17 -080071 LargeSliceAdapter.SliceListView, View.OnClickListener {
Jason Monk8a452e92017-10-31 19:21:47 -040072
Mady Mellorc1334182017-11-10 15:50:35 -080073 private static final String TAG = "RowView";
Jason Monk8a452e92017-10-31 19:21:47 -040074
Mady Mellordb8aa8c2017-11-08 14:26:17 -080075 // The number of items that fit on the right hand side of a small slice
76 private static final int MAX_END_ITEMS = 3;
77
Jason Monk8a452e92017-10-31 19:21:47 -040078 private int mIconSize;
79 private int mPadding;
Mady Mellor71ef84d2017-12-11 13:33:36 -080080 private boolean mInSmallMode;
81 private boolean mIsHeader;
Mady Mellorc1334182017-11-10 15:50:35 -080082
Jason Monk8a452e92017-10-31 19:21:47 -040083 private LinearLayout mStartContainer;
Mady Mellordb8aa8c2017-11-08 14:26:17 -080084 private LinearLayout mContent;
85 private TextView mPrimaryText;
Jason Monk8a452e92017-10-31 19:21:47 -040086 private TextView mSecondaryText;
Mady Mellorc1334182017-11-10 15:50:35 -080087 private View mDivider;
88 private CompoundButton mToggle;
Jason Monk8a452e92017-10-31 19:21:47 -040089 private LinearLayout mEndContainer;
90
Mady Mellorc1334182017-11-10 15:50:35 -080091 private SliceItem mColorItem;
Mady Mellordb8aa8c2017-11-08 14:26:17 -080092 private SliceItem mRowAction;
Mady Mellordb8aa8c2017-11-08 14:26:17 -080093
Mady Mellorc1334182017-11-10 15:50:35 -080094 public RowView(Context context) {
Jason Monk8a452e92017-10-31 19:21:47 -040095 super(context);
Jason Monk8a452e92017-10-31 19:21:47 -040096 mIconSize = getContext().getResources().getDimensionPixelSize(R.dimen.abc_slice_icon_size);
97 mPadding = getContext().getResources().getDimensionPixelSize(R.dimen.abc_slice_padding);
Mady Mellordb8aa8c2017-11-08 14:26:17 -080098 inflate(context, R.layout.abc_slice_small_template, this);
Jason Monk8a452e92017-10-31 19:21:47 -040099
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500100 mStartContainer = (LinearLayout) findViewById(R.id.icon_frame);
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800101 mContent = (LinearLayout) findViewById(android.R.id.content);
102 mPrimaryText = (TextView) findViewById(android.R.id.title);
Jason Monk8a452e92017-10-31 19:21:47 -0400103 mSecondaryText = (TextView) findViewById(android.R.id.summary);
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800104 mDivider = findViewById(R.id.divider);
Jason Monk8a452e92017-10-31 19:21:47 -0400105 mEndContainer = (LinearLayout) findViewById(android.R.id.widget_frame);
106 }
107
108 @Override
Mady Mellor5b2c0ce2017-12-08 12:16:37 -0800109 public View getView() {
110 return this;
111 }
112
113 @Override
Jason Monk8a452e92017-10-31 19:21:47 -0400114 public @SliceView.SliceMode int getMode() {
115 return SliceView.MODE_SMALL;
116 }
117
118 @Override
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800119 public void setColor(SliceItem color) {
120 mColorItem = color;
Jason Monk8a452e92017-10-31 19:21:47 -0400121 }
122
Mady Mellorc1334182017-11-10 15:50:35 -0800123 /**
124 * This is called when RowView is being used as a component in a large template.
125 */
Jason Monk8a452e92017-10-31 19:21:47 -0400126 @Override
Mady Mellorc1334182017-11-10 15:50:35 -0800127 public void setSliceItem(SliceItem slice, boolean isHeader) {
Mady Mellor71ef84d2017-12-11 13:33:36 -0800128 mIsHeader = isHeader;
129 mInSmallMode = false;
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800130 populateViews(slice, slice);
131 }
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500132
Mady Mellorc1334182017-11-10 15:50:35 -0800133 /**
134 * This is called when RowView is being used as a small template.
135 */
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800136 @Override
Jason Monk8a452e92017-10-31 19:21:47 -0400137 public void setSlice(Slice slice) {
Mady Mellor71ef84d2017-12-11 13:33:36 -0800138 mInSmallMode = true;
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800139 Slice.Builder sb = new Slice.Builder(slice.getUri());
140 sb.addSubSlice(slice);
141 Slice parentSlice = sb.build();
Mady Mellor71ef84d2017-12-11 13:33:36 -0800142 populateViews(parentSlice.getItems().get(0), getSummaryItem(slice));
Jason Monk8a452e92017-10-31 19:21:47 -0400143 }
144
Mady Mellor71ef84d2017-12-11 13:33:36 -0800145 private SliceItem getSummaryItem(Slice slice) {
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800146 List<SliceItem> items = slice.getItems();
Mady Mellor71ef84d2017-12-11 13:33:36 -0800147 // See if a summary is specified
148 SliceItem summary = SliceQuery.find(slice, FORMAT_SLICE, HINT_SUMMARY, null);
149 if (summary != null) {
150 return summary;
151 }
152 // First fallback is using a header
Mady Mellorc1334182017-11-10 15:50:35 -0800153 SliceItem header = SliceQuery.find(slice, FORMAT_SLICE, null, HINT_LIST_ITEM);
154 if (header != null) {
155 return header;
156 }
157 // Otherwise use the first non-color item and use it if it's a slice
158 SliceItem firstSlice = null;
159 for (int i = 0; i < items.size(); i++) {
160 if (!FORMAT_COLOR.equals(items.get(i).getFormat())) {
161 firstSlice = items.get(i);
162 break;
163 }
164 }
165 if (firstSlice != null && FORMAT_SLICE.equals(firstSlice.getFormat())) {
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800166 // Check if this slice is appropriate to use to populate small template
Jason Monkdcb5e2f2017-11-15 20:19:43 -0500167 if (firstSlice.hasHint(HINT_LIST)) {
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800168 // Check for header, use that if it exists
Mady Mellorc1334182017-11-10 15:50:35 -0800169 SliceItem listHeader = SliceQuery.find(firstSlice, FORMAT_SLICE,
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800170 null,
171 new String[] {
Jason Monkdcb5e2f2017-11-15 20:19:43 -0500172 HINT_LIST_ITEM, HINT_LIST
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800173 });
Mady Mellorc1334182017-11-10 15:50:35 -0800174 if (listHeader != null) {
175 return SliceQuery.findFirstSlice(listHeader);
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800176 } else {
177 // Otherwise use the first list item
178 SliceItem newFirst = firstSlice.getSlice().getItems().get(0);
179 return SliceQuery.findFirstSlice(newFirst);
180 }
181 } else {
182 // Not a list, find first slice with non-slice children
183 return SliceQuery.findFirstSlice(firstSlice);
Jason Monk8a452e92017-10-31 19:21:47 -0400184 }
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800185 }
Mady Mellorc1334182017-11-10 15:50:35 -0800186 // Fallback, just use this and convert to SliceItem type slice
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800187 Slice.Builder sb = new Slice.Builder(slice.getUri());
188 Slice s = sb.addSubSlice(slice).build();
189 return s.getItems().get(0);
190 }
191
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500192 @TargetApi(24)
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800193 private void populateViews(SliceItem fullSlice, SliceItem sliceItem) {
194 resetViews();
195 ArrayList<SliceItem> items = new ArrayList<>();
Jason Monk0c76d302017-11-21 14:02:27 -0500196 if (FORMAT_SLICE.equals(sliceItem.getFormat())) {
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800197 items = new ArrayList<>(sliceItem.getSlice().getItems());
198 } else {
199 items.add(sliceItem);
200 }
201
202 // These are the things that can go in our small template
203 SliceItem startItem = null;
204 SliceItem titleItem = null;
205 SliceItem subTitle = null;
206 ArrayList<SliceItem> endItems = new ArrayList<>();
207
Mady Mellor71ef84d2017-12-11 13:33:36 -0800208 // If the first item is an action check if it should be used to populate the content
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800209 // or if it should be in the start position.
210 SliceItem firstSlice = items.size() > 0 ? items.get(0) : null;
Jason Monk0c76d302017-11-21 14:02:27 -0500211 if (firstSlice != null && FORMAT_ACTION.equals(firstSlice.getFormat())) {
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800212 if (!SliceQuery.isSimpleAction(firstSlice)) {
213 mRowAction = firstSlice;
214 items.remove(0);
215 // Populating with first action, bias to use slice associated with this action
216 items.addAll(0, mRowAction.getSlice().getItems());
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800217 }
218 }
219
220 // Look through our items and try to figure out main content
221 for (int i = 0; i < items.size(); i++) {
222 SliceItem item = items.get(i);
223 List<String> hints = item.getHints();
Jason Monk0c76d302017-11-21 14:02:27 -0500224 String itemType = item.getFormat();
Mady Mellorc1334182017-11-10 15:50:35 -0800225 if (i == 0 && SliceQuery.isStartType((item))) {
226 startItem = item;
227 } else if (hints.contains(HINT_TITLE)) {
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800228 // Things with these hints could go in the title / start position
Jason Monkdcb5e2f2017-11-15 20:19:43 -0500229 if ((startItem == null || !startItem.hasHint(HINT_TITLE))
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800230 && SliceQuery.isStartType(item)) {
231 startItem = item;
Jason Monkdcb5e2f2017-11-15 20:19:43 -0500232 } else if ((titleItem == null || !titleItem.hasHint(HINT_TITLE))
Jason Monk0c76d302017-11-21 14:02:27 -0500233 && FORMAT_TEXT.equals(itemType)) {
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800234 titleItem = item;
235 } else {
236 endItems.add(item);
237 }
Jason Monk0c76d302017-11-21 14:02:27 -0500238 } else if (FORMAT_TEXT.equals(item.getFormat())) {
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800239 if (titleItem == null) {
240 titleItem = item;
241 } else if (subTitle == null) {
242 subTitle = item;
243 } else {
244 endItems.add(item);
245 }
Jason Monk0c76d302017-11-21 14:02:27 -0500246 } else if (FORMAT_SLICE.equals(item.getFormat())) {
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800247 List<SliceItem> subItems = item.getSlice().getItems();
248 for (int j = 0; j < subItems.size(); j++) {
249 endItems.add(subItems.get(j));
250 }
251 } else {
252 endItems.add(item);
253 }
254 }
255
Mady Mellorc1334182017-11-10 15:50:35 -0800256 SliceItem colorItem = SliceQuery.find(fullSlice, FORMAT_COLOR);
257 int color = colorItem != null
258 ? colorItem.getColor()
259 : (mColorItem != null)
260 ? mColorItem.getColor()
261 : -1;
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800262 // Populate main part of the template
263 if (startItem != null) {
Mady Mellor71ef84d2017-12-11 13:33:36 -0800264 if (!mIsHeader) {
Mady Mellorc1334182017-11-10 15:50:35 -0800265 startItem = addItem(startItem, color, mStartContainer, 0 /* padding */)
266 ? startItem
267 : null;
268 if (startItem != null) {
269 endItems.remove(startItem);
270 }
271 } else {
Mady Mellorc1334182017-11-10 15:50:35 -0800272 endItems.add(0, startItem);
Mady Mellor71ef84d2017-12-11 13:33:36 -0800273 startItem = null;
Mady Mellorc1334182017-11-10 15:50:35 -0800274 }
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800275 }
Mady Mellord2fe91d2017-11-29 11:54:13 -0800276 mStartContainer.setVisibility(startItem != null ? View.VISIBLE : View.GONE);
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800277 if (titleItem != null) {
278 mPrimaryText.setText(titleItem.getText());
279 }
280 mPrimaryText.setVisibility(titleItem != null ? View.VISIBLE : View.GONE);
281 if (subTitle != null) {
282 mSecondaryText.setText(subTitle.getText());
283 }
284 mSecondaryText.setVisibility(subTitle != null ? View.VISIBLE : View.GONE);
285
286 // Figure out what end items we're showing
287 // If we're showing an action in this row check if it's a toggle
Mady Mellorc1334182017-11-10 15:50:35 -0800288 if (mRowAction != null && SliceQuery.hasHints(mRowAction.getSlice(),
289 SliceHints.SUBTYPE_TOGGLE) && addToggle(mRowAction, color)) {
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800290 // Can't show more end actions if we have a toggle so we're done
291 makeClickable(this);
292 return;
293 }
294 // Check if we have a toggle somewhere in our end items
295 SliceItem toggleItem = endItems.stream()
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500296 .filter(new Predicate<SliceItem>() {
297 @Override
298 public boolean test(SliceItem item) {
299 return FORMAT_ACTION.equals(item.getFormat())
Mady Mellorc1334182017-11-10 15:50:35 -0800300 && SliceQuery.hasHints(item.getSlice(), SliceHints.SUBTYPE_TOGGLE);
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500301 }
Mady Mellor71ef84d2017-12-11 13:33:36 -0800302 }).findFirst().orElse(null);
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800303 if (toggleItem != null) {
Mady Mellorc1334182017-11-10 15:50:35 -0800304 if (addToggle(toggleItem, color)) {
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800305 mDivider.setVisibility(mRowAction != null ? View.VISIBLE : View.GONE);
306 makeClickable(mRowAction != null ? mContent : this);
307 // Can't show more end actions if we have a toggle so we're done
308 return;
309 }
310 }
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800311 boolean clickableEndItem = false;
312 int itemCount = 0;
Mady Mellorc1334182017-11-10 15:50:35 -0800313 for (int i = 0; i < endItems.size(); i++) {
314 SliceItem item = endItems.get(i);
Mady Mellor71ef84d2017-12-11 13:33:36 -0800315 // Only show one type of format at the end of the slice, use whatever is first
316 if (itemCount <= MAX_END_ITEMS
317 && item.getFormat().equals(endItems.get(0).getFormat())) {
Mady Mellorc1334182017-11-10 15:50:35 -0800318 if (FORMAT_ACTION.equals(item.getFormat())
319 && itemCount == 0
320 && SliceQuery.hasHints(item.getSlice(), SliceHints.SUBTYPE_TOGGLE)
321 && addToggle(item, color)) {
322 // If a toggle is added we're done
323 break;
324 } else if (addItem(item, color, mEndContainer, mPadding)) {
Jason Monk8a452e92017-10-31 19:21:47 -0400325 itemCount++;
Jason Monk8a452e92017-10-31 19:21:47 -0400326 }
327 }
328 }
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800329 if (mRowAction != null) {
330 makeClickable(clickableEndItem ? mContent : this);
331 }
Jason Monk8a452e92017-10-31 19:21:47 -0400332 }
333
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800334 /**
335 * @return Whether a toggle was added.
336 */
Mady Mellorc1334182017-11-10 15:50:35 -0800337 private boolean addToggle(final SliceItem toggleItem, int color) {
Jason Monk0c76d302017-11-21 14:02:27 -0500338 if (!FORMAT_ACTION.equals(toggleItem.getFormat())
Mady Mellorc1334182017-11-10 15:50:35 -0800339 || !SliceQuery.hasHints(toggleItem.getSlice(), SliceHints.SUBTYPE_TOGGLE)) {
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800340 return false;
Jason Monk8a452e92017-10-31 19:21:47 -0400341 }
Mady Mellorc1334182017-11-10 15:50:35 -0800342
343 // Check if this is a custom toggle
344 Icon checkedIcon = null;
345 List<SliceItem> sliceItems = toggleItem.getSlice().getItems();
346 if (sliceItems.size() > 0) {
347 checkedIcon = FORMAT_IMAGE.equals(sliceItems.get(0).getFormat())
348 ? sliceItems.get(0).getIcon()
349 : null;
350 }
351 if (checkedIcon != null) {
352 if (color != -1) {
353 // TODO - Should these be tinted? What if the app wants diff colors per state?
354 checkedIcon.setTint(color);
355 }
356 mToggle = new ToggleButton(getContext());
357 ((ToggleButton) mToggle).setTextOff("");
358 ((ToggleButton) mToggle).setTextOn("");
359 mToggle.setBackground(checkedIcon.loadDrawable(getContext()));
360 mEndContainer.addView(mToggle);
361 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mToggle.getLayoutParams();
362 lp.width = mIconSize;
363 lp.height = mIconSize;
364 } else {
365 mToggle = new Switch(getContext());
366 mEndContainer.addView(mToggle);
367 }
Jason Monkdcb5e2f2017-11-15 20:19:43 -0500368 mToggle.setChecked(SliceQuery.hasHints(toggleItem.getSlice(), HINT_SELECTED));
Mady Mellorc1334182017-11-10 15:50:35 -0800369 mToggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500370 @Override
371 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
372 try {
373 PendingIntent pi = toggleItem.getAction();
Mady Mellorc1334182017-11-10 15:50:35 -0800374 Intent i = new Intent().putExtra(EXTRA_TOGGLE_STATE, isChecked);
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500375 pi.send(getContext(), 0, i, null, null);
376 } catch (CanceledException e) {
377 mToggle.setSelected(!isChecked);
378 }
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800379 }
380 });
381 return true;
Jason Monk8a452e92017-10-31 19:21:47 -0400382 }
383
384 /**
Mady Mellorc1334182017-11-10 15:50:35 -0800385 * Adds simple items to a container. Simple items include actions with icons, images, or
386 * timestamps.
387 *
388 * @return Whether an item was added to the view.
Jason Monk8a452e92017-10-31 19:21:47 -0400389 */
Mady Mellorc1334182017-11-10 15:50:35 -0800390 private boolean addItem(SliceItem sliceItem, int color, LinearLayout container, int padding) {
Jason Monk8a452e92017-10-31 19:21:47 -0400391 SliceItem image = null;
392 SliceItem action = null;
Mady Mellorc1334182017-11-10 15:50:35 -0800393 SliceItem timeStamp = null;
394 if (FORMAT_ACTION.equals(sliceItem.getFormat())
395 && !sliceItem.hasHint(SliceHints.SUBTYPE_TOGGLE)) {
Jason Monk0c76d302017-11-21 14:02:27 -0500396 image = SliceQuery.find(sliceItem.getSlice(), FORMAT_IMAGE);
Mady Mellorc1334182017-11-10 15:50:35 -0800397 timeStamp = SliceQuery.find(sliceItem.getSlice(), FORMAT_TIMESTAMP);
Jason Monk8a452e92017-10-31 19:21:47 -0400398 action = sliceItem;
Jason Monk0c76d302017-11-21 14:02:27 -0500399 } else if (FORMAT_IMAGE.equals(sliceItem.getFormat())) {
Jason Monk8a452e92017-10-31 19:21:47 -0400400 image = sliceItem;
Mady Mellorc1334182017-11-10 15:50:35 -0800401 } else if (FORMAT_TIMESTAMP.equals(sliceItem.getFormat())) {
402 timeStamp = sliceItem;
Jason Monk8a452e92017-10-31 19:21:47 -0400403 }
Mady Mellorc1334182017-11-10 15:50:35 -0800404 View addedView = null;
Jason Monk8a452e92017-10-31 19:21:47 -0400405 if (image != null) {
406 ImageView iv = new ImageView(getContext());
407 iv.setImageIcon(image.getIcon());
Jason Monkdcb5e2f2017-11-15 20:19:43 -0500408 if (color != -1 && !sliceItem.hasHint(HINT_NO_TINT)) {
Jason Monk8a452e92017-10-31 19:21:47 -0400409 iv.setColorFilter(color);
410 }
411 container.addView(iv);
412 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) iv.getLayoutParams();
413 lp.width = mIconSize;
414 lp.height = mIconSize;
Mady Mellorc1334182017-11-10 15:50:35 -0800415 lp.setMarginStart(padding);
416 addedView = iv;
417 } else if (timeStamp != null) {
418 TextView tv = new TextView(getContext());
419 tv.setText(SliceViewUtil.getRelativeTimeString(sliceItem.getTimestamp()));
420 container.addView(tv);
421 addedView = tv;
Jason Monk8a452e92017-10-31 19:21:47 -0400422 }
Mady Mellorc1334182017-11-10 15:50:35 -0800423 if (action != null && addedView != null) {
424 final SliceItem sliceAction = action;
425 addedView.setOnClickListener(new View.OnClickListener() {
426 @Override
427 public void onClick(View v) {
428 AsyncTask.execute(new Runnable() {
429 @Override
430 public void run() {
431 try {
432 sliceAction.getAction().send();
433 } catch (CanceledException e) {
434 e.printStackTrace();
435 }
436 }
437 });
438 }
439 });
440 addedView.setBackground(SliceViewUtil.getDrawable(getContext(),
441 android.R.attr.selectableItemBackground));
442 }
443 return addedView != null;
Jason Monk8a452e92017-10-31 19:21:47 -0400444 }
445
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800446 @Override
447 public void onClick(View view) {
Jason Monk0c76d302017-11-21 14:02:27 -0500448 if (mRowAction != null && FORMAT_ACTION.equals(mRowAction.getFormat())) {
Mady Mellorc1334182017-11-10 15:50:35 -0800449 // Check for a row action
Jason Monk2a7d0fc2017-11-15 10:10:24 -0500450 AsyncTask.execute(new Runnable() {
451 @Override
452 public void run() {
453 try {
454 mRowAction.getAction().send();
455 } catch (CanceledException e) {
456 Log.w(TAG, "PendingIntent for slice cannot be sent", e);
457 }
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800458 }
459 });
Mady Mellorc1334182017-11-10 15:50:35 -0800460 } else if (mToggle != null) {
461 // Or no row action so let's just toggle if we've got one
462 mToggle.toggle();
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800463 }
464 }
465
466 private void makeClickable(View layout) {
467 layout.setOnClickListener(this);
468 layout.setBackground(SliceViewUtil.getDrawable(getContext(),
469 android.R.attr.selectableItemBackground));
Jason Monk8a452e92017-10-31 19:21:47 -0400470 }
471
472 private void resetViews() {
473 mStartContainer.removeAllViews();
474 mEndContainer.removeAllViews();
Mady Mellordb8aa8c2017-11-08 14:26:17 -0800475 mPrimaryText.setText(null);
Jason Monk8a452e92017-10-31 19:21:47 -0400476 mSecondaryText.setText(null);
Mady Mellorc1334182017-11-10 15:50:35 -0800477 mDivider.setVisibility(View.GONE);
Jason Monk8a452e92017-10-31 19:21:47 -0400478 }
479}