blob: 6e1f0c00b7cac47852a05cd2b9e2eed19135146d [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
Mady Mellor5b2c0ce2017-12-08 12:16:37 -080019import static android.app.slice.Slice.HINT_HORIZONTAL;
Jason Monk98ae4f82017-12-18 11:29:07 -050020import static android.app.slice.Slice.SUBTYPE_COLOR;
21import static android.app.slice.SliceItem.FORMAT_INT;
Jason Monk0c76d302017-11-21 14:02:27 -050022
Jason Monk698ad8c2017-11-10 10:31:19 -050023import android.arch.lifecycle.Observer;
Jason Monk8a452e92017-10-31 19:21:47 -040024import android.content.Context;
Mady Mellor0922d592018-01-23 16:30:59 -080025import android.content.res.TypedArray;
Jason Monk8a452e92017-10-31 19:21:47 -040026import android.graphics.drawable.ColorDrawable;
Jason Monk8a452e92017-10-31 19:21:47 -040027import android.support.annotation.IntDef;
Mady Mellor238b9b62018-01-09 16:15:40 -080028import android.support.annotation.NonNull;
Jason Monk8a452e92017-10-31 19:21:47 -040029import android.support.annotation.Nullable;
30import android.support.annotation.RestrictTo;
Jason Monk8a452e92017-10-31 19:21:47 -040031import android.util.AttributeSet;
32import android.util.Log;
33import android.view.View;
34import android.view.ViewGroup;
Jason Monk8a452e92017-10-31 19:21:47 -040035
36import java.util.List;
37
Jason Monkdcb5e2f2017-11-15 20:19:43 -050038import androidx.app.slice.Slice;
39import androidx.app.slice.SliceItem;
Mady Mellorb794b5b2018-02-07 11:06:48 -080040import androidx.app.slice.SliceUtils;
Jason Monk8a452e92017-10-31 19:21:47 -040041import androidx.app.slice.core.SliceQuery;
42import androidx.app.slice.view.R;
43
44/**
45 * A view for displaying a {@link Slice} which is a piece of app content and actions. SliceView is
46 * able to present slice content in a templated format outside of the associated app. The way this
47 * content is displayed depends on the structure of the slice, the hints associated with the
48 * content, and the mode that SliceView is configured for. The modes that SliceView supports are:
49 * <ul>
50 * <li><b>Shortcut</b>: A shortcut is presented as an icon and a text label representing the main
51 * content or action associated with the slice.</li>
52 * <li><b>Small</b>: The small format has a restricted height and can present a single
53 * {@link SliceItem} or a limited collection of items.</li>
54 * <li><b>Large</b>: The large format displays multiple small templates in a list, if scrolling is
55 * not enabled (see {@link #setScrollable(boolean)}) the view will show as many items as it can
56 * comfortably fit.</li>
57 * </ul>
58 * <p>
59 * When constructing a slice, the contents of it can be annotated with hints, these provide the OS
60 * with some information on how the content should be displayed. For example, text annotated with
Jason Monkdcb5e2f2017-11-15 20:19:43 -050061 * {@link android.app.slice.Slice#HINT_TITLE} would be placed in the title position of a template.
62 * A slice annotated with {@link android.app.slice.Slice#HINT_LIST} would present the child items
63 * of that slice in a list.
Jason Monk8a452e92017-10-31 19:21:47 -040064 * <p>
Jason Monk8a452e92017-10-31 19:21:47 -040065 * Example usage:
66 *
67 * <pre class="prettyprint">
68 * SliceView v = new SliceView(getContext());
69 * v.setMode(desiredMode);
Jason Monk698ad8c2017-11-10 10:31:19 -050070 * LiveData<Slice> liveData = SliceLiveData.fromUri(sliceUri);
71 * liveData.observe(lifecycleOwner, v);
Jason Monk8a452e92017-10-31 19:21:47 -040072 * </pre>
Jason Monk698ad8c2017-11-10 10:31:19 -050073 * @see SliceLiveData
Jason Monk8a452e92017-10-31 19:21:47 -040074 */
Jason Monk698ad8c2017-11-10 10:31:19 -050075public class SliceView extends ViewGroup implements Observer<Slice> {
Jason Monk8a452e92017-10-31 19:21:47 -040076
77 private static final String TAG = "SliceView";
78
79 /**
Mady Mellor238b9b62018-01-09 16:15:40 -080080 * Implement this interface to be notified of interactions with the slice displayed
81 * in this view.
Mady Mellor238b9b62018-01-09 16:15:40 -080082 * @see EventInfo
83 */
Mady Mellorabd7ffd2018-01-10 14:03:45 -080084 public interface OnSliceActionListener {
Mady Mellor238b9b62018-01-09 16:15:40 -080085 /**
86 * Called when an interaction has occurred with an element in this view.
87 * @param info the type of event that occurred.
88 * @param item the specific item within the {@link Slice} that was interacted with.
89 */
90 void onSliceAction(@NonNull EventInfo info, @NonNull SliceItem item);
91 }
92
93 /**
Jason Monk8a452e92017-10-31 19:21:47 -040094 * @hide
95 */
96 @RestrictTo(RestrictTo.Scope.LIBRARY)
Jason Monk8a452e92017-10-31 19:21:47 -040097 @IntDef({
98 MODE_SMALL, MODE_LARGE, MODE_SHORTCUT
99 })
100 public @interface SliceMode {}
101
102 /**
103 * Mode indicating this slice should be presented in small template format.
104 */
105 public static final int MODE_SMALL = 1;
106 /**
107 * Mode indicating this slice should be presented in large template format.
108 */
109 public static final int MODE_LARGE = 2;
110 /**
Mady Mellor24b42962017-11-08 13:27:24 -0800111 * Mode indicating this slice should be presented as an icon. A shortcut requires an intent,
Jason Monkdcb5e2f2017-11-15 20:19:43 -0500112 * icon, and label. This can be indicated by using {@link android.app.slice.Slice#HINT_TITLE}
113 * on an action in a slice.
Jason Monk8a452e92017-10-31 19:21:47 -0400114 */
115 public static final int MODE_SHORTCUT = 3;
116
Mady Mellor8a2763f2018-02-16 13:39:25 -0800117 private int mMode = MODE_LARGE;
Jason Monk8a452e92017-10-31 19:21:47 -0400118 private Slice mCurrentSlice;
Mady Mellorb794b5b2018-02-07 11:06:48 -0800119 private SliceChildView mCurrentView;
120 private List<SliceItem> mActions;
121 private final ActionRow mActionRow;
Jason Monk8a452e92017-10-31 19:21:47 -0400122
Mady Mellorb794b5b2018-02-07 11:06:48 -0800123 private boolean mShowActions = false;
Mady Mellordc052042018-01-04 17:11:07 -0800124 private boolean mIsScrollable = true;
125
Mady Mellorb794b5b2018-02-07 11:06:48 -0800126 private final int mShortcutSize;
Mady Mellor8a2763f2018-02-16 13:39:25 -0800127 private final int mMinLargeHeight;
128
Mady Mellordc052042018-01-04 17:11:07 -0800129 private AttributeSet mAttrs;
Mady Mellorb794b5b2018-02-07 11:06:48 -0800130 private int mThemeTintColor = -1;
131
132 private OnSliceActionListener mSliceObserver;
Mady Mellordc052042018-01-04 17:11:07 -0800133
Jason Monk8a452e92017-10-31 19:21:47 -0400134 public SliceView(Context context) {
135 this(context, null);
136 }
137
138 public SliceView(Context context, @Nullable AttributeSet attrs) {
Mady Mellor0922d592018-01-23 16:30:59 -0800139 this(context, attrs, R.attr.sliceViewStyle);
Jason Monk8a452e92017-10-31 19:21:47 -0400140 }
141
142 public SliceView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
Mady Mellor0922d592018-01-23 16:30:59 -0800143 this(context, attrs, defStyleAttr, R.style.Widget_SliceView);
Jason Monk8a452e92017-10-31 19:21:47 -0400144 }
145
146 public SliceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
147 super(context, attrs, defStyleAttr, defStyleRes);
Mady Mellordc052042018-01-04 17:11:07 -0800148 mAttrs = attrs;
Mady Mellor0922d592018-01-23 16:30:59 -0800149 TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SliceView,
150 defStyleAttr, defStyleRes);
151 try {
152 mThemeTintColor = a.getColor(R.styleable.SliceView_tintColor, -1);
153 } finally {
154 a.recycle();
155 }
Mady Mellorb794b5b2018-02-07 11:06:48 -0800156 // TODO: action row background should support light / dark / maybe presenter customization
157 mActionRow = new ActionRow(getContext(), true);
158 mActionRow.setBackground(new ColorDrawable(0xffeeeeee));
Jason Monk8a452e92017-10-31 19:21:47 -0400159 mCurrentView = new LargeTemplateView(getContext());
Mady Mellor8a2763f2018-02-16 13:39:25 -0800160 mCurrentView.setMode(getMode());
Mady Mellor5b2c0ce2017-12-08 12:16:37 -0800161 addView(mCurrentView.getView(), getChildLp(mCurrentView.getView()));
Mady Mellorb794b5b2018-02-07 11:06:48 -0800162 addView(mActionRow, getChildLp(mActionRow));
Jason Monk8a452e92017-10-31 19:21:47 -0400163 mShortcutSize = getContext().getResources()
164 .getDimensionPixelSize(R.dimen.abc_slice_shortcut_size);
Mady Mellor8a2763f2018-02-16 13:39:25 -0800165 mMinLargeHeight = getResources().getDimensionPixelSize(R.dimen.abc_slice_large_height);
166 }
167
168 private int getHeightForMode() {
169 int mode = getMode();
170 if (mode == MODE_SHORTCUT) {
171 return mShortcutSize;
172 }
173 return mode == MODE_LARGE
174 ? mCurrentView.getActualHeight()
175 : mCurrentView.getSmallHeight();
Jason Monk8a452e92017-10-31 19:21:47 -0400176 }
177
178 @Override
179 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Mady Mellor06dc1412017-11-07 14:34:57 -0800180 int width = MeasureSpec.getSize(widthMeasureSpec);
Mady Mellordc052042018-01-04 17:11:07 -0800181 int childWidth = MeasureSpec.getSize(widthMeasureSpec);
Mady Mellor06dc1412017-11-07 14:34:57 -0800182 if (MODE_SHORTCUT == mMode) {
Mady Mellor8a2763f2018-02-16 13:39:25 -0800183 // TODO: consider scaling the shortcut to fit if too small
Mady Mellordc052042018-01-04 17:11:07 -0800184 childWidth = mShortcutSize;
Mady Mellor06dc1412017-11-07 14:34:57 -0800185 width = mShortcutSize;
186 }
Mady Mellor8a2763f2018-02-16 13:39:25 -0800187
188 final int actionHeight = mActionRow.getVisibility() != View.GONE
189 ? mActionRow.getMeasuredHeight()
190 : 0;
191 final int sliceHeight = getHeightForMode() + actionHeight;
192 final int heightAvailable = MeasureSpec.getSize(heightMeasureSpec);
193 final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
194 int height = heightAvailable;
195 if (heightAvailable >= sliceHeight) {
196 // Available space is larger than the slice
197 if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
198 height = sliceHeight;
199 }
200 } else {
201 // Not enough space available for slice in current mode
202 if (getMode() == MODE_LARGE && heightAvailable >= mMinLargeHeight + actionHeight) {
203 // It's just a slice with scrolling content; cap it to height available.
204 height = heightAvailable;
205 } else if (getMode() == MODE_SHORTCUT) {
206 // TODO: consider scaling the shortcut to fit if too small
207 height = mShortcutSize;
208 }
209 }
210 heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
211
212 // Measure the children without the padding
Mady Mellordc052042018-01-04 17:11:07 -0800213 final int left = getPaddingLeft();
214 final int top = getPaddingTop();
215 final int right = getPaddingRight();
216 final int bot = getPaddingBottom();
Mady Mellor8a2763f2018-02-16 13:39:25 -0800217 int childHeight = MeasureSpec.getSize(heightMeasureSpec);
Mady Mellordc052042018-01-04 17:11:07 -0800218 childWidth -= left + right;
219 childHeight -= top + bot;
220 int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
221 int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY);
222 measureChildren(childWidthMeasureSpec, childHeightMeasureSpec);
223
Mady Mellordc052042018-01-04 17:11:07 -0800224 // Figure out parent width
225 width += left + right;
Mady Mellor8a2763f2018-02-16 13:39:25 -0800226 setMeasuredDimension(width, heightMeasureSpec);
Jason Monk8a452e92017-10-31 19:21:47 -0400227 }
228
229 @Override
230 protected void onLayout(boolean changed, int l, int t, int r, int b) {
Mady Mellor5b2c0ce2017-12-08 12:16:37 -0800231 View v = mCurrentView.getView();
Mady Mellordc052042018-01-04 17:11:07 -0800232 final int left = getPaddingLeft();
233 final int top = getPaddingTop();
234 final int right = getPaddingRight();
235 final int bottom = getPaddingBottom();
236 v.layout(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
Mady Mellorb794b5b2018-02-07 11:06:48 -0800237 if (mActionRow.getVisibility() != View.GONE) {
238 mActionRow.layout(left,
Mady Mellordc052042018-01-04 17:11:07 -0800239 top + v.getMeasuredHeight() + bottom,
Mady Mellorb794b5b2018-02-07 11:06:48 -0800240 left + mActionRow.getMeasuredWidth() + right,
241 top + v.getMeasuredHeight() + bottom + mActionRow.getMeasuredHeight());
Jason Monk8a452e92017-10-31 19:21:47 -0400242 }
243 }
244
Jason Monk698ad8c2017-11-10 10:31:19 -0500245 @Override
246 public void onChanged(@Nullable Slice slice) {
247 setSlice(slice);
Jason Monk8a452e92017-10-31 19:21:47 -0400248 }
249
250 /**
251 * Populates this view to the provided {@link Slice}.
Jason Monk698ad8c2017-11-10 10:31:19 -0500252 *
253 * This will not update automatically if the slice content changes, for live
254 * content see {@link SliceLiveData}.
Jason Monk8a452e92017-10-31 19:21:47 -0400255 */
Jason Monk698ad8c2017-11-10 10:31:19 -0500256 public void setSlice(@Nullable Slice slice) {
Mady Mellorb794b5b2018-02-07 11:06:48 -0800257 if (slice != null) {
258 if (mCurrentSlice == null || mCurrentSlice.getUri() != slice.getUri()) {
259 // New slice, new actions
260 mActions = SliceUtils.getSliceActions(slice);
261 mCurrentView.resetView();
262 }
263 } else {
264 // No slice, no actions
265 mActions = null;
Mady Mellor93ac8cd2018-02-01 11:06:42 -0800266 }
Jason Monk8a452e92017-10-31 19:21:47 -0400267 mCurrentSlice = slice;
268 reinflate();
269 }
270
271 /**
Mady Mellorb794b5b2018-02-07 11:06:48 -0800272 * Returns the slice actions presented in this view.
273 */
274 @Nullable
275 public List<SliceItem> getSliceActions() {
276 return mActions;
277 }
278
279 /**
280 * Sets the slice actions to display for the slice contained in this view. Normally SliceView
281 * will automatically show actions, however, it is possible to reorder or omit actions on the
282 * view using this method. This is generally discouraged.
283 * <p>
284 * It is required that the slice be set on this view before actions can be set, otherwise
285 * this will throw {@link IllegalStateException}. If any of the actions supplied are not
286 * available for the slice set on this view (i.e. the action is not returned by
287 * {@link SliceUtils#getSliceActions(Slice)} this will throw {@link IllegalArgumentException}.
288 */
289 public void setSliceActions(@Nullable List<SliceItem> newActions) {
290 // Check that these actions are part of available set
291 if (mCurrentSlice == null) {
292 throw new IllegalStateException("Trying to set actions on a view without a slice");
293 }
294 List<SliceItem> availableActions = SliceUtils.getSliceActions(mCurrentSlice);
295 if (availableActions != null && newActions != null) {
296 for (int i = 0; i < newActions.size(); i++) {
297 if (!availableActions.contains(newActions.get(i))) {
298 throw new IllegalArgumentException(
299 "Trying to set an action that isn't available: " + newActions.get(i));
300 }
301 }
302 }
303 mActions = newActions;
304 updateActions();
305 }
306
307 /**
Jason Monk8a452e92017-10-31 19:21:47 -0400308 * Set the mode this view should present in.
309 */
310 public void setMode(@SliceMode int mode) {
311 setMode(mode, false /* animate */);
312 }
313
314 /**
315 * Set whether this view should allow scrollable content when presenting in {@link #MODE_LARGE}.
316 */
317 public void setScrollable(boolean isScrollable) {
318 mIsScrollable = isScrollable;
319 reinflate();
320 }
321
322 /**
Mady Mellorabd7ffd2018-01-10 14:03:45 -0800323 * Sets the listener to notify when an interaction events occur on the view.
Mady Mellor238b9b62018-01-09 16:15:40 -0800324 * @see EventInfo
325 */
Mady Mellorabd7ffd2018-01-10 14:03:45 -0800326 public void setOnSliceActionListener(@Nullable OnSliceActionListener observer) {
Mady Mellor238b9b62018-01-09 16:15:40 -0800327 mSliceObserver = observer;
Mady Mellorabd7ffd2018-01-10 14:03:45 -0800328 mCurrentView.setSliceActionListener(mSliceObserver);
Mady Mellor238b9b62018-01-09 16:15:40 -0800329 }
330
331 /**
Mady Mellor0922d592018-01-23 16:30:59 -0800332 * Contents of a slice such as icons, text, and controls (e.g. toggle) can be tinted. Normally
333 * a color for tinting will be provided by the slice. Using this method will override
334 * this color information and instead tint elements with the provided color.
335 *
336 * @param tintColor the color to use for tinting contents of this view.
337 */
338 public void setTint(int tintColor) {
339 mThemeTintColor = tintColor;
340 mCurrentView.setTint(tintColor);
341 }
342
343 /**
Jason Monk8a452e92017-10-31 19:21:47 -0400344 * @hide
345 */
346 @RestrictTo(RestrictTo.Scope.LIBRARY)
347 public void setMode(@SliceMode int mode, boolean animate) {
348 if (animate) {
349 Log.e(TAG, "Animation not supported yet");
350 }
Mady Mellorb794b5b2018-02-07 11:06:48 -0800351 if (mMode == mode) {
352 return;
353 }
Jason Monk8a452e92017-10-31 19:21:47 -0400354 mMode = mode;
355 reinflate();
356 }
357
358 /**
359 * @return the mode this view is presenting in.
360 */
361 public @SliceMode int getMode() {
Jason Monk8a452e92017-10-31 19:21:47 -0400362 return mMode;
363 }
364
365 /**
366 * @hide
367 *
368 * Whether this view should show a row of actions with it.
369 */
370 @RestrictTo(RestrictTo.Scope.LIBRARY)
371 public void setShowActionRow(boolean show) {
372 mShowActions = show;
Mady Mellorb794b5b2018-02-07 11:06:48 -0800373 updateActions();
374 }
375
376 /**
377 * @return whether this view is showing a row of actions.
378 * @hide
379 */
380 @RestrictTo(RestrictTo.Scope.LIBRARY)
381 public boolean isShowingActionRow() {
382 return mShowActions;
Jason Monk8a452e92017-10-31 19:21:47 -0400383 }
384
Mady Mellor9b0a49d2018-02-13 13:55:06 -0800385 private SliceChildView createView(int mode, boolean isGrid) {
Jason Monk8a452e92017-10-31 19:21:47 -0400386 switch (mode) {
387 case MODE_SHORTCUT:
388 return new ShortcutView(getContext());
389 case MODE_SMALL:
Mady Mellor6078df52018-02-12 17:57:33 -0800390 return isGrid ? new GridRowView(getContext()) : new RowView(getContext());
Jason Monk8a452e92017-10-31 19:21:47 -0400391 }
Mady Mellor9b0a49d2018-02-13 13:55:06 -0800392 return new LargeTemplateView(getContext());
Jason Monk8a452e92017-10-31 19:21:47 -0400393 }
394
Jason Monk8a452e92017-10-31 19:21:47 -0400395 private void reinflate() {
396 if (mCurrentSlice == null) {
Mady Mellordf269702017-12-20 15:40:00 -0800397 mCurrentView.resetView();
Jason Monk8a452e92017-10-31 19:21:47 -0400398 return;
399 }
Mady Mellor8a2763f2018-02-16 13:39:25 -0800400 ListContent lc = new ListContent(getContext(), mCurrentSlice);
Mady Mellor9b0a49d2018-02-13 13:55:06 -0800401 if (!lc.isValid()) {
402 mCurrentView.resetView();
403 mCurrentView.setVisibility(View.GONE);
404 return;
405 }
Jason Monk8a452e92017-10-31 19:21:47 -0400406 // TODO: Smarter mapping here from one state to the next.
Jason Monk8a452e92017-10-31 19:21:47 -0400407 int mode = getMode();
Mady Mellor9b0a49d2018-02-13 13:55:06 -0800408 boolean reuseView = mode == mCurrentView.getMode();
409 SliceItem header = lc.getHeaderItem();
410 boolean isSmallGrid = header != null && SliceQuery.hasHints(header, HINT_HORIZONTAL);
411 if (reuseView && mode == MODE_SMALL) {
412 reuseView = (mCurrentView instanceof GridRowView) == isSmallGrid;
413 }
414 if (!reuseView) {
Jason Monk8a452e92017-10-31 19:21:47 -0400415 removeAllViews();
Mady Mellor9b0a49d2018-02-13 13:55:06 -0800416 mCurrentView = createView(mode, isSmallGrid);
Mady Mellor238b9b62018-01-09 16:15:40 -0800417 if (mSliceObserver != null) {
Mady Mellorabd7ffd2018-01-10 14:03:45 -0800418 mCurrentView.setSliceActionListener(mSliceObserver);
Mady Mellor238b9b62018-01-09 16:15:40 -0800419 }
Mady Mellor5b2c0ce2017-12-08 12:16:37 -0800420 addView(mCurrentView.getView(), getChildLp(mCurrentView.getView()));
Mady Mellorb794b5b2018-02-07 11:06:48 -0800421 addView(mActionRow, getChildLp(mActionRow));
Mady Mellor8a2763f2018-02-16 13:39:25 -0800422 mCurrentView.setMode(mode);
Jason Monk8a452e92017-10-31 19:21:47 -0400423 }
Mady Mellordc052042018-01-04 17:11:07 -0800424 // Scrolling
Mady Mellor6078df52018-02-12 17:57:33 -0800425 if (mode == MODE_LARGE && (mCurrentView instanceof LargeTemplateView)) {
Jason Monk8a452e92017-10-31 19:21:47 -0400426 ((LargeTemplateView) mCurrentView).setScrollable(mIsScrollable);
427 }
Mady Mellordc052042018-01-04 17:11:07 -0800428 // Styles
429 mCurrentView.setStyle(mAttrs);
Mady Mellor0922d592018-01-23 16:30:59 -0800430 mCurrentView.setTint(getTintColor());
Mady Mellor9b0a49d2018-02-13 13:55:06 -0800431 mCurrentView.setVisibility(lc.isValid() ? View.VISIBLE : View.GONE);
Mady Mellordc052042018-01-04 17:11:07 -0800432 // Set the slice
Mady Mellorb794b5b2018-02-07 11:06:48 -0800433 mCurrentView.setSlice(mCurrentSlice);
434 updateActions();
435 }
436
437 private void updateActions() {
438 if (mActions == null || mActions.isEmpty()) {
439 // No actions, hide the row, clear out the view
440 mActionRow.setVisibility(View.GONE);
441 mCurrentView.setSliceActions(null);
442 return;
Jason Monk8a452e92017-10-31 19:21:47 -0400443 }
Mady Mellorb794b5b2018-02-07 11:06:48 -0800444
445 // TODO: take priority attached to actions into account
446 if (mShowActions && mMode != MODE_SHORTCUT && mActions.size() >= 2) {
447 // Show in action row if available
448 mActionRow.setActions(mActions, getTintColor());
449 mActionRow.setVisibility(View.VISIBLE);
450 // Hide them on the template
451 mCurrentView.setSliceActions(null);
452 } else if (mActions.size() > 0) {
453 // Otherwise set them on the template
454 mCurrentView.setSliceActions(mActions);
455 mActionRow.setVisibility(View.GONE);
Jason Monk8a452e92017-10-31 19:21:47 -0400456 }
457 }
458
Mady Mellordc052042018-01-04 17:11:07 -0800459 private int getTintColor() {
460 if (mThemeTintColor != -1) {
461 // Theme has specified a color, use that
462 return mThemeTintColor;
463 } else {
464 final SliceItem colorItem = SliceQuery.findSubtype(
465 mCurrentSlice, FORMAT_INT, SUBTYPE_COLOR);
466 return colorItem != null
467 ? colorItem.getInt()
468 : SliceViewUtil.getColorAccent(getContext());
469 }
470 }
471
Jason Monk8a452e92017-10-31 19:21:47 -0400472 private LayoutParams getChildLp(View child) {
473 if (child instanceof ShortcutView) {
474 return new LayoutParams(mShortcutSize, mShortcutSize);
475 } else {
Mady Mellor8a2763f2018-02-16 13:39:25 -0800476 return new LayoutParams(LayoutParams.MATCH_PARENT,
477 LayoutParams.MATCH_PARENT);
Jason Monk8a452e92017-10-31 19:21:47 -0400478 }
479 }
480
Mady Mellor238b9b62018-01-09 16:15:40 -0800481 /**
482 * @return String representation of the provided mode.
483 * @hide
484 */
485 @RestrictTo(RestrictTo.Scope.LIBRARY)
486 public static String modeToString(@SliceMode int mode) {
487 switch(mode) {
Mady Mellor238b9b62018-01-09 16:15:40 -0800488 case MODE_SHORTCUT:
489 return "MODE SHORTCUT";
490 case MODE_SMALL:
491 return "MODE SMALL";
492 case MODE_LARGE:
493 return "MODE LARGE";
494 default:
495 return "unknown mode: " + mode;
496 }
497 }
Jason Monk8a452e92017-10-31 19:21:47 -0400498}