/* * Copyright 2017 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.slice.builders; import static androidx.annotation.RestrictTo.Scope.LIBRARY; import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; import android.app.PendingIntent; import android.content.Context; import android.graphics.drawable.Icon; import android.net.Uri; import androidx.annotation.ColorInt; import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.annotation.RestrictTo; import androidx.core.graphics.drawable.IconCompat; import androidx.core.util.Consumer; import androidx.slice.SliceSpecs; import androidx.slice.builders.impl.ListBuilderBasicImpl; import androidx.slice.builders.impl.ListBuilderV1Impl; import androidx.slice.builders.impl.TemplateBuilderImpl; import androidx.slice.core.SliceHints; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; /** * A slice can be constructed with ListBuilder. *
* A slice is a piece of templated app content that can be presented outside of the app * in a {@link androidx.slice.widget.SliceView}. To provide a slice you should implement a * {@link androidx.slice.SliceProvider} and use ListBuilder to construct your slice when * {@link androidx.slice.SliceProvider#onBindSlice(Uri)} is called. *
* ListBuilder allows you to construct a slice made up of rows of content. A list should * have at least one row of content as well as a primary {@link SliceAction}. The row types that * ListBuilder supports are: *
* In addition to rows of content, ListBuilder can also have {@link SliceAction}s added to it. These * actions may appear differently on your slice depending on how the * {@link androidx.slice.widget.SliceView} is configured. Normally the actions would appear in * the header. *
* To ensure your slice is presented correctly you should consider the configurations * {@link androidx.slice.widget.SliceView} supports: *
* Note that scrolling on SliceView can be disabled, in which case only the header and one or two * rows of content may be shown for your slice. If your slice contains many rows of content to * scroll through (e.g. list of wifi networks), consider using * {@link #addSeeMoreAction(PendingIntent)} to provide a link to open the activity associated with * the content. * * @see HeaderBuilder * @see RowBuilder * @see GridRowBuilder * @see RangeBuilder * @see InputRangeBuilder * @see SliceAction * @see androidx.slice.SliceProvider * @see androidx.slice.SliceProvider#onBindSlice(Uri) * @see androidx.slice.widget.SliceView */ public class ListBuilder extends TemplateSliceBuilder { private boolean mHasSeeMore; private androidx.slice.builders.impl.ListBuilder mImpl; /** * @hide */ @RestrictTo(RestrictTo.Scope.LIBRARY) @IntDef({ LARGE_IMAGE, SMALL_IMAGE, ICON_IMAGE, UNKNOWN_IMAGE }) @Retention(RetentionPolicy.SOURCE) public @interface ImageMode{} /** * Indicates that an image should be presented as an icon and it can be tinted. */ public static final int ICON_IMAGE = SliceHints.ICON_IMAGE; /** * Indicates that an image should be presented in a smaller size and it shouldn't be tinted. */ public static final int SMALL_IMAGE = SliceHints.SMALL_IMAGE; /** * Indicates that an image presented in a larger size and it shouldn't be tinted. */ public static final int LARGE_IMAGE = SliceHints.LARGE_IMAGE; /** * Indicates that an image mode is unknown. */ public static final int UNKNOWN_IMAGE = SliceHints.UNKNOWN_IMAGE; /** * Constant representing infinity. */ public static final long INFINITY = SliceHints.INFINITY; /** * Create a builder which will construct a slice made up of rows of content. * * @param uri Uri to tag for this slice. * * @deprecated TO BE REMOVED; use {@link #ListBuilder(Context, Uri, long)}. */ @Deprecated public ListBuilder(@NonNull Context context, @NonNull Uri uri) { super(context, uri); } /** * Create a builder which will construct a slice that will display rows of content. *
* A slice requires an associated time-to-live, i.e. how long the data contained in the slice
* can remain fresh. If your slice has content that is not time sensitive, set a TTL of
* {@link #INFINITY}.
*
* @param uri Uri to tag for this slice.
* @param ttl the length in milliseconds that the content in this slice can live for.
*/
public ListBuilder(@NonNull Context context, @NonNull Uri uri, long ttl) {
super(context, uri);
mImpl.setTtl(ttl);
}
@Override
void setImpl(TemplateBuilderImpl impl) {
mImpl = (androidx.slice.builders.impl.ListBuilder) impl;
}
/**
* Add a row to the list builder.
*/
@NonNull
public ListBuilder addRow(@NonNull RowBuilder builder) {
mImpl.addRow((TemplateBuilderImpl) builder.mImpl);
return this;
}
/**
* Add a row to the list builder.
*/
@NonNull
public ListBuilder addRow(@NonNull Consumer
* In MODE_SMALL, the header row shown if one has been added. The header will also
* display the {@link HeaderBuilder#setSummary(CharSequence)} text if it has been
* specified, allowing a summary of otherwise hidden content to be shown.
*
* In MODE_SHORTCUT, the primary action set using
* {@link HeaderBuilder#setPrimaryAction(SliceAction)} will be used for the shortcut
* representation.
*
* @see HeaderBuilder#setSummary(CharSequence)
*/
@NonNull
public ListBuilder setHeader(@NonNull HeaderBuilder builder) {
mImpl.setHeader((TemplateBuilderImpl) builder.mImpl);
return this;
}
/**
* Sets a header for this list builder. A list can have only one header. Setting a header allows
* some flexibility in what's displayed in your slice when SliceView displays in
* {@link androidx.slice.widget.SliceView#MODE_SMALL} and
* {@link androidx.slice.widget.SliceView#MODE_SHORTCUT}.
*
* In MODE_SMALL, the header row shown if one has been added. The header will also
* display the {@link HeaderBuilder#setSummary(CharSequence)} text if it has been
* specified, allowing a summary of otherwise hidden content to be shown.
*
* In MODE_SHORTCUT, the primary action set using
* {@link HeaderBuilder#setPrimaryAction(SliceAction)} will be used for the shortcut
* representation.
*
* @see HeaderBuilder#setSummary(CharSequence)
*/
@NonNull
public ListBuilder setHeader(@NonNull Consumer
* Actions added with this method are grouped together on the list template. These actions may
* appear differently on the slice depending on how the {@link androidx.slice.widget.SliceView}
* is configured. Generally these actions will be displayed in the order they were added,
* however, if not all actions can be displayed then actions with a higher priority may be shown
* first.
*
* @see SliceAction
* @see SliceAction#setPriority(int)
* @see androidx.slice.widget.SliceView#setActions(List, int)
*/
@NonNull
public ListBuilder addAction(@NonNull SliceAction action) {
mImpl.addAction(action);
return this;
}
/**
* @deprecated TO BE REMOVED; use {@link #setAccentColor(int)} instead.
*/
@Deprecated
@NonNull
public ListBuilder setColor(@ColorInt int color) {
return setAccentColor(color);
}
/**
* Sets the color to use on tintable items within the list builder.
* Things that might be tinted are:
*
* This method should only be used if you want to display a customized row to indicate more
* content, consider using {@link #addSeeMoreAction(PendingIntent)} otherwise. If you do
* choose to specify a custom row, the row should have a content intent or action end item
* specified to take the user to an activity to see all of the content. The row added here
* will only appear when not all content can be displayed and it will not be styled any
* differently from row built by {@link RowBuilder} normally.
*
* Only one see more affordance can be added, this throws {@link IllegalStateException} if
* a row or action has been previously added.
*
* This method should only be used if you want to display a customized row to indicate more
* content, consider using {@link #addSeeMoreAction(PendingIntent)} otherwise. If you do
* choose to specify a custom row, the row should have a content intent or action end item
* specified to take the user to an activity to see all of the content. The row added here
* will only appear when not all content can be displayed and it will not be styled any
* differently from row built by {@link RowBuilder} normally.
*
* Only one see more affordance can be added, this throws {@link IllegalStateException} if
* a row or action has been previously added.
*
* This method should only be used if you want to display a custom row to indicate more
* content, consider using {@link #addSeeMoreAction(PendingIntent)} otherwise. If you do
* choose to specify a custom row, the row should have a content intent or action end item
* specified to take the user to an activity to see all of the content.
*
* Only one see more affordance can be added, this throws {@link IllegalStateException} if
* a row or action has been previously added.
*
* This method should only be used if you want to display a custom row to indicate more
* content, consider using {@link #addSeeMoreAction(PendingIntent)} otherwise. If you do
* choose to specify a custom row, the row should have a content intent or action end item
* specified to take the user to an activity to see all of the content.
*
*
*/
@NonNull
public ListBuilder setAccentColor(@ColorInt int color) {
mImpl.setColor(color);
return this;
}
/**
* Sets keywords to associate with this slice.
*/
@NonNull
public ListBuilder setKeywords(List
* Only one see more affordance can be added, this throws {@link IllegalStateException} if * a row or action has been previously added. *
* * @deprecated TO BE REMOVED */ @Deprecated @NonNull public ListBuilder addSeeMoreAction(@NonNull PendingIntent intent) { if (mHasSeeMore) { throw new IllegalArgumentException("Trying to add see more action when one has " + "already been added"); } mImpl.setSeeMoreAction(intent); mHasSeeMore = true; return this; } /** * @hide */ @RestrictTo(LIBRARY) @Override protected TemplateBuilderImpl selectImpl() { if (checkCompatible(SliceSpecs.LIST)) { return new ListBuilderV1Impl(getBuilder(), SliceSpecs.LIST); } else if (checkCompatible(SliceSpecs.BASIC)) { return new ListBuilderBasicImpl(getBuilder(), SliceSpecs.BASIC); } return null; } /** * @hide */ @RestrictTo(LIBRARY) public androidx.slice.builders.impl.ListBuilder getImpl() { return mImpl; } /** * Add an input range row to the list builder. */ @NonNull public ListBuilder addInputRange(@NonNull InputRangeBuilder b) { mImpl.addInputRange((TemplateBuilderImpl) b.mImpl); return this; } /** * Add an input range row to the list builder. */ @NonNull public ListBuilder addInputRange(@NonNull Consumer* A range row supports displaying a horizontal progress indicator. * * @see ListBuilder#addRange(Consumer) * @see ListBuilder#addRange(RangeBuilder) */ public static class RangeBuilder extends TemplateSliceBuilder { private androidx.slice.builders.impl.ListBuilder.RangeBuilder mImpl; /** * Builder to construct a range row which can be added to a {@link ListBuilder}. *
* A range row supports displaying a horizontal progress indicator. * * @see ListBuilder#addRange(Consumer) * @see ListBuilder#addRange(RangeBuilder) */ public RangeBuilder(@NonNull ListBuilder parent) { super(parent.mImpl.createRangeBuilder()); } /** * Set the upper limit of the range. The default is 100. */ @NonNull public RangeBuilder setMax(int max) { mImpl.setMax(max); return this; } /** * Set the current value of the range. */ @NonNull public RangeBuilder setValue(int value) { mImpl.setValue(value); return this; } /** * Set the title. */ @NonNull public RangeBuilder setTitle(@NonNull CharSequence title) { mImpl.setTitle(title); return this; } /** * Set the subtitle. */ @NonNull public RangeBuilder setSubtitle(@NonNull CharSequence title) { mImpl.setSubtitle(title); return this; } /** * Set the primary action for this row. *
* The action specified here will be sent when the whole row is clicked. If this * is the first row in a {@link ListBuilder} this action will also be used to define * the {@link androidx.slice.widget.SliceView#MODE_SHORTCUT} representation of the slice. */ @NonNull public RangeBuilder setPrimaryAction(@NonNull SliceAction action) { mImpl.setPrimaryAction(action); return this; } /** * Sets the content description. */ @NonNull public RangeBuilder setContentDescription(@NonNull CharSequence description) { mImpl.setContentDescription(description); return this; } @Override void setImpl(TemplateBuilderImpl impl) { mImpl = (androidx.slice.builders.impl.ListBuilder.RangeBuilder) impl; } } /** * Builder to construct a input range row. *
* An input range row supports displaying a horizontal slider allowing slider input. * * @see ListBuilder#addInputRange(Consumer) * @see ListBuilder#addInputRange(InputRangeBuilder) */ public static class InputRangeBuilder extends TemplateSliceBuilder { private androidx.slice.builders.impl.ListBuilder.InputRangeBuilder mImpl; /** * Builder to construct a input range row. *
* An input range row supports displaying a horizontal slider allowing slider input. * * @see ListBuilder#addInputRange(Consumer) * @see ListBuilder#addInputRange(InputRangeBuilder) */ public InputRangeBuilder(@NonNull ListBuilder parent) { super(parent.mImpl.createInputRangeBuilder()); } /** * Set the lower limit of the range. The default is 0. */ @NonNull public InputRangeBuilder setMin(int min) { mImpl.setMin(min); return this; } /** * Set the upper limit of the range. The default is 100. */ @NonNull public InputRangeBuilder setMax(int max) { mImpl.setMax(max); return this; } /** * Set the current value of the range. */ @NonNull public InputRangeBuilder setValue(int value) { mImpl.setValue(value); return this; } /** * Set the title. */ @NonNull public InputRangeBuilder setTitle(@NonNull CharSequence title) { mImpl.setTitle(title); return this; } /** * Set the subtitle. */ @NonNull public InputRangeBuilder setSubtitle(@NonNull CharSequence title) { mImpl.setSubtitle(title); return this; } /** * Set the {@link PendingIntent} to send when the current value is updated. * * @deprecated TO BE REMOVED; use {@link InputRangeBuilder#setInputAction(PendingIntent)} */ @Deprecated @NonNull public InputRangeBuilder setAction(@NonNull PendingIntent action) { mImpl.setInputAction(action); return this; } /** * Set the {@link PendingIntent} to send when the current value is updated. */ @NonNull public InputRangeBuilder setInputAction(@NonNull PendingIntent action) { mImpl.setInputAction(action); return this; } /** * @deprecated TO BE REMOVED */ @NonNull @RequiresApi(23) public InputRangeBuilder setThumb(@NonNull Icon thumb) { return setThumb(IconCompat.createFromIcon(thumb)); } /** * Set the {@link Icon} to be displayed as the thumb on the input range. */ @NonNull public InputRangeBuilder setThumb(@NonNull IconCompat thumb) { mImpl.setThumb(thumb); return this; } /** * Set the primary action for this row. *
* The action specified here will be sent when the whole row is clicked, whereas * the action specified via {@link #setAction(PendingIntent)} is used when the slider * is interacted with. Additionally, if this is the first row in a {@link ListBuilder} this * action will also be used to define the * {@link androidx.slice.widget.SliceView#MODE_SHORTCUT} representation of the slice. */ @NonNull public InputRangeBuilder setPrimaryAction(@NonNull SliceAction action) { mImpl.setPrimaryAction(action); return this; } /** * Sets the content description. */ @NonNull public InputRangeBuilder setContentDescription(@NonNull CharSequence description) { mImpl.setContentDescription(description); return this; } @Override void setImpl(TemplateBuilderImpl impl) { mImpl = (androidx.slice.builders.impl.ListBuilder.InputRangeBuilder) impl; } } /** * Builder to construct a row. A row can be added as an item to ListBuilder via * {@link ListBuilder#addRow(RowBuilder)}. *
* A row supports: *
* There can only be one title item, this will replace any other title * items that may have been set. */ @NonNull public RowBuilder setTitleItem(long timeStamp) { if (mHasTimestamp) { throw new IllegalArgumentException("Trying to add a timestamp when one has " + "already been added"); } mImpl.setTitleItem(timeStamp); mHasTimestamp = true; return this; } /** * @deprecated TO BE REMOVED. */ @Deprecated @NonNull @RequiresApi(23) public RowBuilder setTitleItem(@NonNull Icon icon) { return setTitleItem(icon, ICON_IMAGE); } /** * @deprecated TO BE REMOVED. */ @Deprecated @NonNull @RequiresApi(23) public RowBuilder setTitleItem(@Nullable Icon icon, boolean isLoading) { return setTitleItem(icon, ICON_IMAGE, isLoading); } /** * @deprecated TO BE REMOVED. */ @Deprecated @RequiresApi(23) public RowBuilder setTitleItem(@NonNull Icon icon, @ImageMode int imageMode) { mImpl.setTitleItem(IconCompat.createFromIcon(icon), imageMode, false /* isLoading */); return this; } /** * @deprecated TO BE REMOVED. */ @Deprecated @NonNull @RequiresApi(23) public RowBuilder setTitleItem(@Nullable Icon icon, @ImageMode int imageMode, boolean isLoading) { mImpl.setTitleItem(IconCompat.createFromIcon(icon), imageMode, isLoading /* isLoading */); return this; } /** * Sets the title item to be the provided icon. There can only be one title item, this * will replace any other title items that may have been set. * * @deprecated TO BE REMOVED; use ListBuilder{@link #setTitleItem(Icon, int, boolean)}. */ @Deprecated @NonNull public RowBuilder setTitleItem(@NonNull IconCompat icon) { return setTitleItem(icon, ICON_IMAGE); } /** * Sets the title item to be the provided icon. There can only be one title item, this * will replace any other title items that may have been set. *
* Use this method to specify content that will appear in the template once it's been * loaded. *
* @param isLoading indicates whether the app is doing work to load the added content in the * background or not. * * @deprecated TO BE REMOVED; use ListBuilder{@link #setTitleItem(Icon, int, boolean)}. */ @Deprecated @NonNull public RowBuilder setTitleItem(@Nullable IconCompat icon, boolean isLoading) { return setTitleItem(icon, ICON_IMAGE, isLoading); } /** * Sets the title item to be the provided icon. There can only be one title item, this * will replace any other title items that may have been set. * * @param icon the image to display. * @param imageMode the mode that image should be displayed in. * * @see #ICON_IMAGE * @see #SMALL_IMAGE * @see #LARGE_IMAGE */ public RowBuilder setTitleItem(@NonNull IconCompat icon, @ImageMode int imageMode) { mImpl.setTitleItem(icon, imageMode, false /* isLoading */); return this; } /** * Sets the title item to be the provided icon. There can only be one title item, this * will replace any other title items that may have been set. ** When set to true, the parameter {@code isLoading} indicates that the app is doing work * to load this content in the background, in this case the template displays a placeholder * until updated. * * @param icon the image to display. * @param imageMode the mode that image should be displayed in. * @param isLoading whether this content is being loaded in the background. * * @see #ICON_IMAGE * @see #SMALL_IMAGE * @see #LARGE_IMAGE */ @NonNull public RowBuilder setTitleItem(@Nullable IconCompat icon, @ImageMode int imageMode, boolean isLoading) { mImpl.setTitleItem(icon, imageMode, isLoading /* isLoading */); return this; } /** * Sets the title item to be a tappable icon. There can only be one title item, this will * replace any other title items that may have been set. */ @NonNull public RowBuilder setTitleItem(@NonNull SliceAction action) { return setTitleItem(action, false /* isLoading */); } /** * Sets the title item to be a tappable icon. There can only be one title item, this will * replace any other title items that may have been set. *
* Use this method to specify content that will appear in the template once it's been * loaded. *
* @param isLoading indicates whether the app is doing work to load the added content in the * background or not. */ @NonNull public RowBuilder setTitleItem(@NonNull SliceAction action, boolean isLoading) { mImpl.setTitleItem(action, isLoading); return this; } /** * The action specified here will be sent when the whole row is clicked. ** If this is the first row in a {@link ListBuilder} this action will also be used to define * the {@link androidx.slice.widget.SliceView#MODE_SHORTCUT} representation of the slice. */ @NonNull public RowBuilder setPrimaryAction(@NonNull SliceAction action) { mImpl.setPrimaryAction(action); return this; } /** * Sets the title for the row builder. */ @NonNull public RowBuilder setTitle(@NonNull CharSequence title) { mImpl.setTitle(title); return this; } /** * Sets the title for the row builder. *
* Use this method to specify content that will appear in the template once it's been * loaded. *
* @param isLoading indicates whether the app is doing work to load the added content in the * background or not. */ @NonNull public RowBuilder setTitle(@Nullable CharSequence title, boolean isLoading) { mImpl.setTitle(title, isLoading); return this; } /** * Sets the subtitle for the row builder. */ @NonNull public RowBuilder setSubtitle(@NonNull CharSequence subtitle) { return setSubtitle(subtitle, false /* isLoading */); } /** * Sets the subtitle for the row builder. ** Use this method to specify content that will appear in the template once it's been * loaded. *
* @param isLoading indicates whether the app is doing work to load the added content in the * background or not. */ @NonNull public RowBuilder setSubtitle(@Nullable CharSequence subtitle, boolean isLoading) { mImpl.setSubtitle(subtitle, isLoading); return this; } /** * Adds a timestamp to the end items of the row builder. Only one timestamp can be added, * if one is already added this will throw {@link IllegalArgumentException}. */ @NonNull public RowBuilder addEndItem(long timeStamp) { if (mHasTimestamp) { throw new IllegalArgumentException("Trying to add a timestamp when one has " + "already been added"); } mImpl.addEndItem(timeStamp); mHasTimestamp = true; return this; } /** * @deprecated TO BE REMOVED */ @Deprecated @NonNull @RequiresApi(23) public RowBuilder addEndItem(@NonNull Icon icon) { return addEndItem(icon, ICON_IMAGE, false /* isLoading */); } /** * @deprecated TO BE REMOVED */ @Deprecated @NonNull @RequiresApi(23) public RowBuilder addEndItem(@NonNull Icon icon, boolean isLoading) { return addEndItem(icon, ICON_IMAGE, isLoading); } /** * @deprecated TO BE REMOVED */ @Deprecated @NonNull @RequiresApi(23) public RowBuilder addEndItem(@NonNull Icon icon, @ImageMode int imageMode) { return addEndItem(icon, imageMode, false /* isLoading */); } /** * @deprecated TO BE REMOVED */ @Deprecated @NonNull @RequiresApi(23) public RowBuilder addEndItem(@Nullable Icon icon, @ImageMode int imageMode, boolean isLoading) { if (mHasEndActionOrToggle) { throw new IllegalArgumentException("Trying to add an icon to end items when an" + "action has already been added. End items cannot have a mixture of " + "actions and icons."); } mImpl.addEndItem(IconCompat.createFromIcon(icon), imageMode, isLoading); mHasEndImage = true; return this; } /** * Adds an icon to the end items of the row builder. A mixture of icons and actions * is not permitted. If an action has already been added this will throw * {@link IllegalArgumentException}. * * @deprecated use ListBuilder{@link #addEndItem(Icon, int)} instead. */ @Deprecated @NonNull public RowBuilder addEndItem(@NonNull IconCompat icon) { return addEndItem(icon, ICON_IMAGE, false /* isLoading */); } /** * Adds an icon to be displayed at the end of the row. A mixture of icons and actions * is not permitted. If an action has already been added this will throw * {@link IllegalArgumentException}. ** Use this method to specify content that will appear in the template once it's been * loaded. *
* @param isLoading indicates whether the app is doing work to load the added content in the * background or not. * * @deprecated use ListBuilder{@link #addEndItem(Icon, int, boolean)} instead. */ @Deprecated @NonNull public RowBuilder addEndItem(@NonNull IconCompat icon, boolean isLoading) { return addEndItem(icon, ICON_IMAGE, isLoading); } /** * Adds an icon to the end items of the row builder. * * @param icon the image to display. * @param imageMode the mode that image should be displayed in. * * @see #ICON_IMAGE * @see #SMALL_IMAGE * @see #LARGE_IMAGE */ @NonNull public RowBuilder addEndItem(@NonNull IconCompat icon, @ImageMode int imageMode) { return addEndItem(icon, imageMode, false /* isLoading */); } /** * Adds an icon to the end items of the row builder. ** When set to true, the parameter {@code isLoading} indicates that the app is doing work * to load this content in the background, in this case the template displays a placeholder * until updated. * * @param icon the image to display. * @param imageMode the mode that image should be displayed in. * @param isLoading whether this content is being loaded in the background. * * @see #ICON_IMAGE * @see #SMALL_IMAGE * @see #LARGE_IMAGE */ @NonNull public RowBuilder addEndItem(@Nullable IconCompat icon, @ImageMode int imageMode, boolean isLoading) { if (mHasEndActionOrToggle) { throw new IllegalArgumentException("Trying to add an icon to end items when an" + "action has already been added. End items cannot have a mixture of " + "actions and icons."); } mImpl.addEndItem(icon, imageMode, isLoading); mHasEndImage = true; return this; } /** * Adds an action to the end items of the row builder. A mixture of icons and * actions is not permitted. If an icon has already been added, this will throw * {@link IllegalArgumentException}. */ @NonNull public RowBuilder addEndItem(@NonNull SliceAction action) { return addEndItem(action, false /* isLoading */); } /** * Adds an action to the end items of the row builder. A mixture of icons and * actions is not permitted. If an icon has already been added, this will throw * {@link IllegalArgumentException}. *
* Use this method to specify content that will appear in the template once it's been * loaded. *
* @param isLoading indicates whether the app is doing work to load the added content in the * background or not. */ @NonNull public RowBuilder addEndItem(@NonNull SliceAction action, boolean isLoading) { if (mHasEndImage) { throw new IllegalArgumentException("Trying to add an action to end items when an" + "icon has already been added. End items cannot have a mixture of " + "actions and icons."); } if (mHasDefaultToggle) { throw new IllegalStateException("Only one non-custom toggle can be added " + "in a single row. If you would like to include multiple toggles " + "in a row, set a custom icon for each toggle."); } mImpl.addEndItem(action, isLoading); mHasDefaultToggle = action.getImpl().isDefaultToggle(); mHasEndActionOrToggle = true; return this; } /** * Sets the content description for the row. */ @NonNull public RowBuilder setContentDescription(@NonNull CharSequence description) { mImpl.setContentDescription(description); return this; } @Override void setImpl(TemplateBuilderImpl impl) { mImpl = (androidx.slice.builders.impl.ListBuilder.RowBuilder) impl; } /** * @hide */ @RestrictTo(LIBRARY) public androidx.slice.builders.impl.ListBuilder.RowBuilder getImpl() { return mImpl; } } /** * Builder to construct a header row. ** A header provides some additional functionality compared to a {@link RowBuilder}. Like * a row, a header has a title, subtitle, and primary action. *
* In addition to a row's title, subtitle, and primary action, a header also supports setting * a summary description of the list contents using * {@link HeaderBuilder#setSummary(CharSequence)}. This summary might be used when * the rest of the list content is not shown (e.g. if SliceView presenting slice is * configured to {@link androidx.slice.widget.SliceView#MODE_SMALL}. *
* The primary action specified by {@link HeaderBuilder#setPrimaryAction(SliceAction)} will * be used as the PendingIntent sent when header is clicked. This action is also used when * when SliceView displays in {@link androidx.slice.widget.SliceView#MODE_SHORTCUT}. *
* Unlike row builder, header builder does not support end items (e.g. * {@link RowBuilder#addEndItem(SliceAction)}). The header may be used to display actions set * on the list via {@link #addAction(SliceAction)}. * * @see ListBuilder#setHeader(HeaderBuilder) * @see ListBuilder#addAction(SliceAction) * @see SliceAction */ public static class HeaderBuilder extends TemplateSliceBuilder { private androidx.slice.builders.impl.ListBuilder.HeaderBuilder mImpl; /** * Create builder for a header. */ public HeaderBuilder(@NonNull ListBuilder parent) { super(parent.mImpl.createHeaderBuilder()); } /** * Create builder for a header. * @hide */ @RestrictTo(LIBRARY_GROUP) public HeaderBuilder(@NonNull ListBuilder parent, @NonNull Uri uri) { super(parent.mImpl.createHeaderBuilder(uri)); } /** * Sets the title for the header builder. */ @NonNull public HeaderBuilder setTitle(@NonNull CharSequence title) { return setTitle(title, false /* isLoading */); } /** * Sets the title for the header builder. *
* Use this method to specify content that will appear in the template once it's been * loaded. *
* @param isLoading indicates whether the app is doing work to load the added content in the * background or not. */ @NonNull public HeaderBuilder setTitle(@NonNull CharSequence title, boolean isLoading) { mImpl.setTitle(title, isLoading); return this; } /** * Sets the subtitle for the header builder. */ @NonNull public HeaderBuilder setSubtitle(@NonNull CharSequence subtitle) { return setSubtitle(subtitle, false /* isLoading */); } /** * Sets the subtitle for the header builder. ** Use this method to specify content that will appear in the template once it's been * loaded. *
* @param isLoading indicates whether the app is doing work to load the added content in the * background or not. */ @NonNull public HeaderBuilder setSubtitle(@NonNull CharSequence subtitle, boolean isLoading) { mImpl.setSubtitle(subtitle, isLoading); return this; } /** * Sets the summary subtitle to be shown in this header. If unset, the normal subtitle * will be used. The summary is used when the parent template is presented in a * small format. * @deprecated TO BE REMOVED; use {@link #setSummary(CharSequence)} */ @NonNull public HeaderBuilder setSummarySubtitle(@NonNull CharSequence summarySubtitle) { return setSummary(summarySubtitle, false /* isLoading */); } /** * Sets the summary subtitle to be shown in this header. If unset, the normal subtitle * will be used. The summary is used when the parent template is presented in a * small format. * @deprecated TO BE REMOVED; use {@link #setSummary(CharSequence, boolean)} */ @NonNull public HeaderBuilder setSummarySubtitle(@NonNull CharSequence summarySubtitle, boolean isLoading) { return setSummary(summarySubtitle, isLoading /* isLoading */); } /** * Sets the summary for the header builder. A summary is optional. ** The summary should be a description of the contents of the list. This summary might be * used when the rest of the list content is not shown (e.g. if SliceView presenting slice * is configured to {@link androidx.slice.widget.SliceView#MODE_SMALL}. */ @NonNull public HeaderBuilder setSummary(@NonNull CharSequence summary) { return setSummary(summary, false /* isLoading */); } /** * Sets the summary for the header builder. A summary is optional. *
* The summary should be a description of the contents of the list. This summary might be * used when the rest of the list content is not shown (e.g. if SliceView presenting slice * is configured to {@link androidx.slice.widget.SliceView#MODE_SMALL}. *
* Use this method to specify content that will appear in the template once it's been * loaded. *
* @param isLoading indicates whether the app is doing work to load the added content in the * background or not. */ @NonNull public HeaderBuilder setSummary(@NonNull CharSequence summary, boolean isLoading) { mImpl.setSummary(summary, isLoading); return this; } /** * Sets the action to send when the header is clicked. ** Additionally, the action specified here is used when the slice associated with this * header is displayed in {@link androidx.slice.widget.SliceView#MODE_SHORTCUT}. */ @NonNull public HeaderBuilder setPrimaryAction(@NonNull SliceAction action) { mImpl.setPrimaryAction(action); return this; } /** * Sets the content description for the header. */ @NonNull public HeaderBuilder setContentDescription(@NonNull CharSequence description) { mImpl.setContentDescription(description); return this; } @Override void setImpl(TemplateBuilderImpl impl) { mImpl = (androidx.slice.builders.impl.ListBuilder.HeaderBuilder) impl; } } }