• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 
17 package com.android.tv.twopanelsettings.slices.builders;
18 
19 import static com.android.tv.twopanelsettings.slices.SlicesConstants.BUTTONSTYLE;
20 import static com.android.tv.twopanelsettings.slices.SlicesConstants.CHECKMARK;
21 import static com.android.tv.twopanelsettings.slices.SlicesConstants.RADIO;
22 import static com.android.tv.twopanelsettings.slices.SlicesConstants.SEEKBAR;
23 import static com.android.tv.twopanelsettings.slices.SlicesConstants.SWITCH;
24 
25 import android.app.PendingIntent;
26 import android.content.Context;
27 import android.net.Uri;
28 import android.view.View;
29 
30 import androidx.annotation.IntDef;
31 import androidx.annotation.NonNull;
32 import androidx.annotation.Nullable;
33 import androidx.annotation.RestrictTo;
34 import androidx.core.graphics.drawable.IconCompat;
35 import androidx.core.util.Pair;
36 import androidx.slice.Slice;
37 import androidx.slice.SliceSpecs;
38 import androidx.slice.builders.ListBuilder;
39 import androidx.slice.builders.SliceAction;
40 import androidx.slice.core.SliceHints;
41 
42 import java.lang.annotation.Retention;
43 import java.lang.annotation.RetentionPolicy;
44 import java.time.Duration;
45 import java.util.ArrayList;
46 import java.util.List;
47 
48 // TODO: Remove unused code and add test.
49 /**
50  * Builder for constructing slices composed of rows of TvSettings style preferences.
51  */
52 public class PreferenceSliceBuilder extends TemplateSliceBuilder {
53 
54     private PreferenceSliceBuilderImpl mImpl;
55 
56     /**
57      * Constant representing infinity.
58      */
59     public static final long INFINITY = SliceHints.INFINITY;
60 
61     /**
62      * @hide
63      */
64     @RestrictTo(RestrictTo.Scope.LIBRARY)
65     @IntDef({
66         View.LAYOUT_DIRECTION_RTL, View.LAYOUT_DIRECTION_LTR, View.LAYOUT_DIRECTION_INHERIT,
67         View.LAYOUT_DIRECTION_LOCALE
68     })
69     @Retention(RetentionPolicy.SOURCE)
70     public @interface LayoutDirection {
71 
72     }
73 
74     /**
75      * Create a builder which will construct a slice made up of rows of content.
76      *
77      * @param uri Uri to tag for this slice.
78      * @hide
79      */
PreferenceSliceBuilder(@onNull Context context, @NonNull Uri uri)80     public PreferenceSliceBuilder(@NonNull Context context, @NonNull Uri uri) {
81         super(context, uri);
82     }
83 
84     /**
85      * Create a ListBuilder for constructing slice content.
86      * <p>
87      * A slice requires an associated time-to-live, i.e. how long the data contained in the slice
88      * can remain fresh. If your slice has content that is not time sensitive, set a TTL of {@link
89      * #INFINITY}.
90      *
91      * @param uri Uri to tag for this slice.
92      * @param ttl the length in milliseconds that the content in this slice can live for.
93      */
PreferenceSliceBuilder(@onNull Context context, @NonNull Uri uri, long ttl)94     public PreferenceSliceBuilder(@NonNull Context context, @NonNull Uri uri, long ttl) {
95         super(context, uri);
96         mImpl.setTtl(ttl);
97     }
98 
99     /**
100      * Create a ListBuilder for constructing slice content.
101      * <p>
102      * A slice requires an associated time-to-live, i.e. how long the data contained in the slice
103      * can remain fresh. If your slice has content that is not time sensitive, set {@link Duration}
104      * to null and the TTL will be {@link #INFINITY}.
105      *
106      * @param uri Uri to tag for this slice.
107      * @param ttl the {@link Duration} that the content in this slice can live for.
108      */
PreferenceSliceBuilder(@onNull Context context, @NonNull Uri uri, @Nullable Duration ttl)109     public PreferenceSliceBuilder(@NonNull Context context, @NonNull Uri uri,
110             @Nullable Duration ttl) {
111         super(context, uri);
112         mImpl.setTtl(ttl);
113     }
114 
115     @Override
selectImpl(Uri uri)116     protected TemplateBuilderImpl selectImpl(Uri uri) {
117         return new PreferenceSliceBuilderImpl(getBuilder(), SliceSpecs.LIST, getClock());
118     }
119 
120     /**
121      * Construct the slice defined by this PreferenceSliceBuilder
122      */
123     @NonNull
124     @Override
build()125     public Slice build() {
126         return mImpl.build();
127     }
128 
129     @Override
setImpl(TemplateBuilderImpl impl)130     void setImpl(TemplateBuilderImpl impl) {
131         mImpl = (PreferenceSliceBuilderImpl) impl;
132     }
133 
134     /**
135      * Add a preference builder. If the row is expected to be actionable, it is recommended to
136      * invoke setActionId() for the RowBuilder to help with logging.
137      */
addPreference(RowBuilder builder)138     public PreferenceSliceBuilder addPreference(RowBuilder builder) {
139         mImpl.addPreference(builder);
140         return this;
141     }
142 
143     /**
144      * Add a preferenceCategory builder.
145      */
addPreferenceCategory(RowBuilder builder)146     public PreferenceSliceBuilder addPreferenceCategory(RowBuilder builder) {
147         mImpl.addPreferenceCategory(builder);
148         return this;
149     }
150 
151     /**
152      * Set a custom screen title for slice. It is recommended to invoke setPageId() for the
153      * RowBuilder in addition to setTitle(), to help with logging.
154      */
addScreenTitle(RowBuilder builder)155     public PreferenceSliceBuilder addScreenTitle(RowBuilder builder) {
156         mImpl.addScreenTitle(builder);
157         return this;
158     }
159 
160     /**
161      * Add an embedded preference placeholder where another slice can control the properties via
162      * setEmbeddedPreference.
163      */
addEmbeddedPreference(RowBuilder builder)164     public PreferenceSliceBuilder addEmbeddedPreference(RowBuilder builder) {
165         mImpl.addEmbeddedPreference(builder);
166         return this;
167     }
168 
169     /**
170      * Set the focused preference for slice.
171      * @param key key of the focused preference.
172      */
setFocusedPreference(CharSequence key)173     public PreferenceSliceBuilder setFocusedPreference(CharSequence key) {
174         mImpl.setFocusedPreference(key);
175         return this;
176     }
177 
178     /** Add a preference which can be embedded in other settings items. **/
setEmbeddedPreference(RowBuilder builder)179     public PreferenceSliceBuilder setEmbeddedPreference(RowBuilder builder) {
180         mImpl.setEmbeddedPreference(builder);
181         return this;
182     }
183 
184     /** Indicates that the slice is not ready yet **/
setNotReady()185     public PreferenceSliceBuilder setNotReady() {
186         mImpl.setNotReady();
187         return this;
188     }
189 
190 
191     /**
192      * Set the redirected slice uri. Settings would render the slice from the redirected slice uri.
193      * @param redirectedSliceUri the redirected slice uri.
194      */
195     @NonNull
setRedirectedSliceUri(@onNull CharSequence redirectedSliceUri)196     public PreferenceSliceBuilder setRedirectedSliceUri(@NonNull CharSequence redirectedSliceUri) {
197         mImpl.setRedirectedSliceUri(redirectedSliceUri);
198         return this;
199     }
200 
201     public static class RowBuilder {
202 
203         private final Uri mUri;
204         private boolean mHasEndActionOrToggle;
205         private boolean mHasEndImage;
206         private boolean mHasDefaultToggle;
207         private boolean mHasEndIcon;
208         private boolean mTitleItemLoading;
209         private IconCompat mTitleIcon;
210         private SliceAction mTitleAction;
211         private SliceAction mPrimaryAction;
212         private SliceAction mFollowupAction;
213         private int mActionId;
214         private int mPageId;
215         private CharSequence mTitle;
216         private boolean mTitleLoading;
217         private CharSequence mSubtitle;
218         private boolean mSubtitleLoading;
219         private CharSequence mContentDescription;
220         private CharSequence mInfoTitle;
221         private CharSequence mInfoSummary;
222         private IconCompat mInfoImage;
223         private IconCompat mInfoTitleIcon;
224         private int mLayoutDirection = -1;
225         private List<Object> mEndItems = new ArrayList<>();
226         private List<Integer> mEndTypes = new ArrayList<>();
227         private List<Boolean> mEndLoads = new ArrayList<>();
228         private List<Pair<String, String>> mInfoItems = new ArrayList<>();
229         private boolean mTitleActionLoading;
230         private CharSequence mTargetSliceUri;
231         private CharSequence mKey;
232         private boolean mIconNeedsToBeProcessed;
233         private @BUTTONSTYLE int mButtonStyle;
234         private int mSeekbarMin;
235         private int mSeekbarMax;
236         private int mSeekbarValue;
237         private CharSequence mRadioGroup;
238         private boolean mEnabled;
239         private boolean mSelectable;
240         private boolean mAddInfoStatus;
241         private CharSequence mRedirectSliceUri;
242 
243         public static final int TYPE_ICON = 1;
244         public static final int TYPE_ACTION = 2;
245 
246         /**
247          * Builder to construct a row.
248          */
RowBuilder()249         public RowBuilder() {
250             mEnabled = true;
251             mSelectable = true;
252             mUri = null;
253         }
254 
255         /**
256          * Builder to construct a normal row.
257          *
258          * @param uri Uri to tag for this slice.
259          */
RowBuilder(Uri uri)260         public RowBuilder(Uri uri) {
261             mEnabled = true;
262             mSelectable = true;
263             mUri = uri;
264         }
265 
266         /**
267          * Builder to construct a row.
268          *
269          * @param parent The builder constructing the parent slice.
270          */
RowBuilder(@onNull ListBuilder parent)271         public RowBuilder(@NonNull ListBuilder parent) {
272             this();
273         }
274 
275         /**
276          * Builder to construct a row.
277          *
278          * @param uri Uri to tag for this slice.
279          */
RowBuilder(@onNull ListBuilder parent, @NonNull Uri uri)280         public RowBuilder(@NonNull ListBuilder parent, @NonNull Uri uri) {
281             this(uri);
282         }
283 
284         /**
285          * Builder to construct a normal row.
286          *
287          * @param uri Uri to tag for this slice.
288          */
RowBuilder(@onNull Context context, @NonNull Uri uri)289         public RowBuilder(@NonNull Context context, @NonNull Uri uri) {
290             this(uri);
291         }
292 
293         /**
294          * Sets the title item to be the provided icon. There can only be one title item, this will
295          * replace any other title items that may have been set.
296          *
297          * @param icon the image to display.
298          */
setTitleItem(@onNull IconCompat icon)299         private RowBuilder setTitleItem(@NonNull IconCompat icon) {
300             return setTitleItem(icon, false /* isLoading */);
301         }
302 
303         /**
304          * Sets the title item to be the provided icon. There can only be one title item, this will
305          * replace any other title items that may have been set.
306          * <p>
307          * When set to true, the parameter {@code isLoading} indicates that the app is doing work to
308          * load this content in the background, in this case the template displays a placeholder
309          * until updated.
310          *
311          * @param icon the image to display.
312          * @param isLoading whether this content is being loaded in the background.
313          */
314         @NonNull
setTitleItem(@ullable IconCompat icon, boolean isLoading)315         private RowBuilder setTitleItem(@Nullable IconCompat icon, boolean isLoading) {
316             mTitleAction = null;
317             mTitleIcon = icon;
318             mTitleItemLoading = isLoading;
319             return this;
320         }
321 
322         /**
323          * Sets the title item to be a tappable icon. There can only be one title item, this will
324          * replace any other title items that may have been set.
325          */
326         @NonNull
setTitleItem(@onNull SliceAction action)327         private RowBuilder setTitleItem(@NonNull SliceAction action) {
328             return setTitleItem(action, false /* isLoading */);
329         }
330 
331         /**
332          * Sets the title item to be a tappable icon. There can only be one title item, this will
333          * replace any other title items that may have been set.
334          * <p>
335          * Use this method to specify content that will appear in the template once it's been
336          * loaded.
337          * </p>
338          *
339          * @param isLoading indicates whether the app is doing work to load the added content in the
340          * background or not.
341          */
342         @NonNull
setTitleItem(@onNull SliceAction action, boolean isLoading)343         private RowBuilder setTitleItem(@NonNull SliceAction action, boolean isLoading) {
344             mTitleAction = action;
345             mTitleIcon = null;
346             mTitleActionLoading = isLoading;
347             return this;
348         }
349 
350         /**
351          * Sets the icon for the preference builder. There can only be one icon,
352          * this will replace any other icon that may have been set.
353          * This means that you should only provide an icon using one of the two functions
354          * {@link #setIcon(IconCompat)} or {@link #setEndIcon(IconCompat)}.
355          *
356          * @param icon the image to display.
357          */
358         @NonNull
setIcon(@onNull IconCompat icon)359         public RowBuilder setIcon(@NonNull IconCompat icon) {
360             mHasEndIcon = false;
361             return setTitleItem(icon);
362         }
363 
364         /**
365          * Sets the icon to the end for the preference builder. There can only be one icon,
366          * this will replace any other icon that may have been set.
367          * This means that you should only provide an icon using one of the two functions
368          * {@link #setIcon(IconCompat)} or {@link #setEndIcon(IconCompat)}.
369          *
370          * @param icon the image to display.
371          */
372         @NonNull
setEndIcon(@onNull IconCompat icon)373         public RowBuilder setEndIcon(@NonNull IconCompat icon) {
374             mHasEndIcon = true;
375             return setTitleItem(icon);
376         }
377 
378         /**
379          * Set the information image for the preference builder.
380          * The image would be displayed at the top of preview screen.
381          */
382         @NonNull
setInfoImage(@onNull IconCompat icon)383         public RowBuilder setInfoImage(@NonNull IconCompat icon) {
384             mInfoImage = icon;
385             return this;
386         }
387 
388         /**
389          * Set the information title icon for the preference builder.
390          * The icon will be displayed to the left of description text title
391          */
392         @NonNull
setInfoTitleIcon(@onNull IconCompat icon)393         public RowBuilder setInfoTitleIcon(@NonNull IconCompat icon) {
394             mInfoTitleIcon = icon;
395             return this;
396         }
397 
398         /**
399          * Set the information text for the preference builder.
400          */
401         @Deprecated
402         @NonNull
setInfoText(CharSequence text)403         public RowBuilder setInfoText(CharSequence text) {
404             mInfoTitle = text;
405             return this;
406         }
407 
408         /**
409          * Set the information text title for the preference builder.
410          *
411          * It is strongly recommended to also invoke setContentDescription() for a11y
412          * purposes. Please see setContentDescription() for more details.
413          */
414         @NonNull
setInfoTitle(CharSequence text)415         public RowBuilder setInfoTitle(CharSequence text) {
416             mInfoTitle = text;
417             return this;
418         }
419 
420         /**
421          * Set the information text summary for the preference builder.
422          *
423          * It is strongly recommended to also invoke setContentDescription() for a11y
424          * purposes. Please see setContentDescription() for more details.
425          */
426         @NonNull
setInfoSummary(CharSequence text)427         public RowBuilder setInfoSummary(CharSequence text) {
428             mInfoSummary = text;
429             return this;
430         }
431 
432         /**
433          * Set whether need to add info status. If set true, info status would be automatically
434          * generated based upon the on/off status of the switch.
435          */
436         @NonNull
setAddInfoStatus(boolean addInfoStatus)437         public RowBuilder setAddInfoStatus(boolean addInfoStatus) {
438             mAddInfoStatus = addInfoStatus;
439             return this;
440         }
441 
442         /**
443          * The action specified here will be sent when the whole row is clicked.
444          * <p>
445          * If this is the first row in a {@link ListBuilder} this action will also be used to define
446          * the {@link androidx.slice.widget.SliceView#MODE_SHORTCUT} representation of the slice.
447          */
448         @NonNull
setPrimaryAction(@onNull SliceAction action)449         private RowBuilder setPrimaryAction(@NonNull SliceAction action) {
450             mPrimaryAction = action;
451             return this;
452         }
453 
454         /**
455          * Set a pendingIntent for the preference builder.
456          * @param pendingIntent pendingIntent
457          * @return builder
458          */
459         @NonNull
setPendingIntent(@onNull PendingIntent pendingIntent)460         public RowBuilder setPendingIntent(@NonNull PendingIntent pendingIntent) {
461             return setPrimaryAction(new SliceAction(pendingIntent, "", false));
462         }
463 
464         /**
465          * Set a followup pendingIntent for the preference builder. After the initial pendingIntent
466          * is launched and result is retrieved by TvSettings, TvSettings will pack the result into
467          * the followup PendingIntent and launch it.
468          * @param pendingIntent followup pendingIntent
469          * @return builder
470          */
471         @NonNull
setFollowupPendingIntent(@onNull PendingIntent pendingIntent)472         public RowBuilder setFollowupPendingIntent(@NonNull PendingIntent pendingIntent) {
473             mFollowupAction = new SliceAction(pendingIntent, "", false);
474             return this;
475         }
476 
477         /**
478          * Set the action ID for the row builder. If this is invoked for building an actionable row,
479          * it will be digested as actionId for logging purpose when the action is triggered.
480          *
481          * @param actionId pre-defined ID of an action
482          */
483         @NonNull
setActionId(int actionId)484         public RowBuilder setActionId(int actionId) {
485             mActionId = actionId;
486             return this;
487         }
488 
489         /**
490          * Set the page ID for the row builder. If this is invoked for building the screen title
491          * row, it will be digested as pageId for logging purpose when the SliceFragment is focused.
492          *
493          * @param pageId pre-defined ID of a page
494          */
495         @NonNull
setPageId(int pageId)496         public RowBuilder setPageId(int pageId) {
497             mPageId = pageId;
498             return this;
499         }
500 
501         /**
502          * Sets the title for the row builder. A title should fit on a single line and is ellipsized
503          * if too long.
504          */
505         @NonNull
setTitle(@onNull CharSequence title)506         public RowBuilder setTitle(@NonNull CharSequence title) {
507             return setTitle(title, false);
508         }
509 
510         /**
511          * Sets the title for the row builder. A title should fit on a single line and is ellipsized
512          * if too long.
513          * <p>
514          * Use this method to specify content that will appear in the template once it's been
515          * loaded.
516          * </p>
517          *
518          * @param isLoading indicates whether the app is doing work to load the added content in the
519          * background or not.
520          */
521         @NonNull
setTitle(@ullable CharSequence title, boolean isLoading)522         public RowBuilder setTitle(@Nullable CharSequence title, boolean isLoading) {
523             mTitle = title;
524             mTitleLoading = isLoading;
525             return this;
526         }
527 
528         /**
529          * Sets the subtitle for the row builder. A subtitle should fit on a single line and is
530          * ellipsized if too long.
531          */
532         @NonNull
setSubtitle(@onNull CharSequence subtitle)533         public RowBuilder setSubtitle(@NonNull CharSequence subtitle) {
534             return setSubtitle(subtitle, false /* isLoading */);
535         }
536 
537         /**
538          * Sets the subtitle for the row builder. A subtitle should fit on a single line and is
539          * ellipsized if too long.
540          * <p>
541          * Use this method to specify content that will appear in the template once it's been
542          * loaded.
543          * </p>
544          *
545          * @param isLoading indicates whether the app is doing work to load the added content in the
546          * background or not.
547          */
548         @NonNull
setSubtitle(@ullable CharSequence subtitle, boolean isLoading)549         public RowBuilder setSubtitle(@Nullable CharSequence subtitle, boolean isLoading) {
550             mSubtitle = subtitle;
551             mSubtitleLoading = isLoading;
552             return this;
553         }
554 
555         /**
556          * Adds an icon to the end items of the row builder.
557          *
558          * @param icon the image to display.
559          */
560         @NonNull
addEndItem(@onNull IconCompat icon)561         private RowBuilder addEndItem(@NonNull IconCompat icon) {
562             return addEndItem(icon, false /* isLoading */);
563         }
564 
565         /**
566          * Adds an icon to the end items of the row builder.
567          * <p>
568          * When set to true, the parameter {@code isLoading} indicates that the app is doing work to
569          * load this content in the background, in this case the template displays a placeholder
570          * until updated.
571          *
572          * @param icon the image to display.
573          * @param isLoading whether this content is being loaded in the background.
574          */
575         @NonNull
addEndItem(@ullable IconCompat icon, boolean isLoading)576         private RowBuilder addEndItem(@Nullable IconCompat icon, boolean isLoading) {
577             if (mHasEndActionOrToggle) {
578                 throw new IllegalArgumentException("Trying to add an icon to end items when an"
579                     + "action has already been added. End items cannot have a mixture of "
580                     + "actions and icons.");
581             }
582             mEndItems.add(new Pair<>(icon, 0));
583             mEndTypes.add(TYPE_ICON);
584             mEndLoads.add(isLoading);
585             mHasEndImage = true;
586             return this;
587         }
588 
589         /**
590          * Adds an action to the end items of the row builder. A mixture of icons and actions is not
591          * permitted. If an icon has already been added, this will throw {@link
592          * IllegalArgumentException}.
593          */
594         @NonNull
addEndItem(@onNull SliceAction action)595         private RowBuilder addEndItem(@NonNull SliceAction action) {
596             return addEndItem(action, false /* isLoading */);
597         }
598 
599 
600         /**
601          * Add an item to the RowBuilder. Each item would contain title and summary.
602          */
addInfoItem(String title, String summary)603         public RowBuilder addInfoItem(String title, String summary) {
604             mInfoItems.add(new Pair<>(title, summary));
605             return this;
606         }
607 
608         /**
609          * Add a radio button to the RowBuilder.
610          * @param pendingIntent pendingIntent to launch when radio is clicked.
611          * @param isChecked Initial state of the radio button
612          */
addRadioButton( PendingIntent pendingIntent, boolean isChecked)613         public RowBuilder addRadioButton(
614                 PendingIntent pendingIntent, boolean isChecked) {
615             return addButton(pendingIntent, isChecked, RADIO);
616         }
617 
618         /**
619          * Add a radio button to the RowBuilder.
620          * @param pendingIntent pendingIntent to launch when radio is clicked.
621          * @param isChecked Initial state of the radio button
622          * @param radioGroup group of the radio
623          */
addRadioButton( PendingIntent pendingIntent, boolean isChecked, CharSequence radioGroup)624         public RowBuilder addRadioButton(
625                 PendingIntent pendingIntent, boolean isChecked, CharSequence radioGroup) {
626             return addButton(pendingIntent, isChecked, RADIO).setRadioGroup(radioGroup);
627         }
628 
629         /**
630          * Add a checkmark to the RowBuilder.
631          * @param pendingIntent pendingIntent to launch when checkmark is clicked.
632          * @param isChecked Initial state of the check mark.
633          */
addCheckMark( PendingIntent pendingIntent, boolean isChecked)634         public RowBuilder addCheckMark(
635                 PendingIntent pendingIntent, boolean isChecked) {
636             return addButton(pendingIntent, isChecked, CHECKMARK);
637         }
638 
639         /**
640          * Add a switch to the RowBuilder.
641          * @param pendingIntent pendingIntent to launch when switch is clicked.
642          * @param isChecked Initial state of the switch.
643          */
addSwitch( PendingIntent pendingIntent, boolean isChecked)644         public RowBuilder addSwitch(
645                 PendingIntent pendingIntent, boolean isChecked) {
646             return addButton(pendingIntent, isChecked, SWITCH);
647         }
648 
addButton( PendingIntent pendingIntent, boolean isChecked, @BUTTONSTYLE int style)649         private RowBuilder addButton(
650                 PendingIntent pendingIntent, boolean isChecked, @BUTTONSTYLE int style) {
651             SliceAction switchAction = new SliceAction(pendingIntent, "", isChecked);
652             mButtonStyle = style;
653             return addEndItem(switchAction);
654         }
655 
656         /**
657          * Add a switch for the preference.
658          * @param pendingIntent pendingIntent
659          * @param actionTitle title for the switch, also used for contentDescription.
660          * @param isChecked the state of the switch
661          * @return
662          */
663         @NonNull
addSwitch( PendingIntent pendingIntent, @NonNull CharSequence actionTitle, boolean isChecked)664         public PreferenceSliceBuilder.RowBuilder addSwitch(
665                 PendingIntent pendingIntent, @NonNull CharSequence actionTitle, boolean isChecked) {
666             SliceAction switchAction = new SliceAction(pendingIntent, actionTitle, isChecked);
667             mButtonStyle = SWITCH;
668             return addEndItem(switchAction);
669         }
670 
addSeekBar( PendingIntent pendingIntent, int min, int max, int value)671         public PreferenceSliceBuilder.RowBuilder addSeekBar(
672                 PendingIntent pendingIntent, int min, int max, int value) {
673             SliceAction seekbarAction = new SliceAction(pendingIntent, "", false);
674             mButtonStyle = SEEKBAR;
675             mSeekbarMin = min;
676             mSeekbarMax = max;
677             mSeekbarValue = value;
678             return addEndItem(seekbarAction);
679         }
680 
681         /**
682          * Adds an action to the end items of the row builder. A mixture of icons and actions is not
683          * permitted. If an icon has already been added, this will throw {@link
684          * IllegalArgumentException}.
685          * <p>
686          * Use this method to specify content that will appear in the template once it's been
687          * loaded.
688          * </p>
689          *
690          * @param isLoading indicates whether the app is doing work to load the added content in the
691          * background or not.
692          */
693         @NonNull
addEndItem(@onNull SliceAction action, boolean isLoading)694         private RowBuilder addEndItem(@NonNull SliceAction action, boolean isLoading) {
695             if (mHasEndImage) {
696                 throw new IllegalArgumentException("Trying to add an action to end items when an"
697                     + "icon has already been added. End items cannot have a mixture of "
698                     + "actions and icons.");
699             }
700             if (mHasDefaultToggle) {
701                 throw new IllegalStateException("Only one non-custom toggle can be added "
702                     + "in a single row. If you would like to include multiple toggles "
703                     + "in a row, set a custom icon for each toggle.");
704             }
705             mEndItems.add(action);
706             mEndTypes.add(TYPE_ACTION);
707             mEndLoads.add(isLoading);
708             mHasDefaultToggle = action.getImpl().isDefaultToggle();
709             mHasEndActionOrToggle = true;
710             return this;
711         }
712 
713         /**
714          * Sets the content description for the row.
715          *
716          * Although TvSettings will try to construct the content description to its best extent
717          * if it's not set, it is strongly recommended to invoke this method with info items
718          * folded in the content description for the Roy for a11y purposes, as the info items
719          * may be unfocusable when talkback is on.
720          *
721          * By default, this method will assign the full info item title and summary to the
722          * content description if one is not specified.
723          */
724         @NonNull
setContentDescription(@onNull CharSequence description)725         public RowBuilder setContentDescription(@NonNull CharSequence description) {
726             mContentDescription = description;
727             return this;
728         }
729 
730         /**
731          * Set the target slice uri for the builder.
732          * @param targetSliceUri indicates the target slice uri when the preference is focused.
733          * @return builder
734          */
setTargetSliceUri(@onNull CharSequence targetSliceUri)735         public RowBuilder setTargetSliceUri(@NonNull CharSequence targetSliceUri) {
736             mTargetSliceUri = targetSliceUri;
737             return this;
738         }
739 
740         /**
741          * Set the key for the builder.
742          * @param key indicates the key for the preference.
743          * @return builder
744          */
setKey(@onNull CharSequence key)745         public RowBuilder setKey(@NonNull CharSequence key) {
746             mKey = key;
747             return this;
748         }
749 
750         /**
751          * Sets the desired layout direction for the content in this row.
752          *
753          * @param layoutDirection the layout direction to set.
754          */
755         @NonNull
setLayoutDirection(@ayoutDirection int layoutDirection)756         public RowBuilder setLayoutDirection(@LayoutDirection int layoutDirection) {
757             mLayoutDirection = layoutDirection;
758             return this;
759         }
760 
761         /**
762          * Set whether the toggle use a checkmark style. Otherwise, a switch style is used.
763          * @param isCheckMark use checkmark.
764          * @deprecated use {@link PreferenceSliceBuilder.RowBuilder#setButtonStyle(int)}
765          */
766         @Deprecated
767         @NonNull
setCheckmark(boolean isCheckMark)768         public RowBuilder setCheckmark(boolean isCheckMark) {
769             if (isCheckMark) {
770                 mButtonStyle = CHECKMARK;
771             } else {
772                 mButtonStyle = SWITCH;
773             }
774             return this;
775         }
776 
777         /**
778          * Set the button style.
779          * @param buttonStyle
780          */
setButtonStyle(@UTTONSTYLE int buttonStyle)781         public RowBuilder setButtonStyle(@BUTTONSTYLE int buttonStyle) {
782             mButtonStyle = buttonStyle;
783             return this;
784         }
785 
786         /**
787          * Set whether the icon needs to be processed by TvSettings.
788          * @param needed if true, TvSettings will add a round border around the given icon
789          */
790         @NonNull
setIconNeedsToBeProcessed(boolean needed)791         public RowBuilder setIconNeedsToBeProcessed(boolean needed) {
792             mIconNeedsToBeProcessed = needed;
793             return this;
794         }
795 
796         /**
797          * Set radio group for radio
798          */
799         @NonNull
setRadioGroup(CharSequence radioGroup)800         public RowBuilder setRadioGroup(CharSequence radioGroup) {
801             mRadioGroup = radioGroup;
802             return this;
803         }
804 
805         /**
806          * Set whether this item is enabled.
807          */
808         @NonNull
setEnabled(boolean enabled)809         public RowBuilder setEnabled(boolean enabled) {
810             mEnabled = enabled;
811             return this;
812         }
813 
814         /**
815          * Set whether this item is selectable.
816          * @param selectable
817          */
818         @NonNull
setSelectable(boolean selectable)819         public RowBuilder setSelectable(boolean selectable) {
820             mSelectable = selectable;
821             return this;
822         }
823 
824         /**
825          *
826          */
iconNeedsToBeProcessed()827         public boolean iconNeedsToBeProcessed() {
828             return mIconNeedsToBeProcessed;
829         }
830 
831         /**
832          *
833          */
getButtonStyle()834         public int getButtonStyle() {
835             return mButtonStyle;
836         }
837 
838         /**
839          *
840          */
getSeekbarMin()841         public int getSeekbarMin() {
842             return mSeekbarMin;
843         }
844 
845         /**
846          *
847          */
getSeekbarMax()848         public int getSeekbarMax() {
849             return mSeekbarMax;
850         }
851 
852         /**
853          *
854          */
getSeekbarValue()855         public int getSeekbarValue() {
856             return mSeekbarValue;
857         }
858 
859         /**
860          * Get the target slice uri.
861          */
getTargetSliceUri()862         public CharSequence getTargetSliceUri() {
863             return mTargetSliceUri;
864         }
865 
866         /** Get the key for the builder */
getKey()867         public CharSequence getKey() {
868             return mKey;
869         }
870 
getUri()871         public Uri getUri() {
872             return mUri;
873         }
874 
hasEndActionOrToggle()875         public boolean hasEndActionOrToggle() {
876             return mHasEndActionOrToggle;
877         }
878 
hasEndImage()879         public boolean hasEndImage() {
880             return mHasEndImage;
881         }
882 
hasDefaultToggle()883         public boolean hasDefaultToggle() {
884             return mHasDefaultToggle;
885         }
886 
887         /**
888          * Checks if item has an end icon.
889          */
hasEndIcon()890         public boolean hasEndIcon() {
891             return mHasEndIcon;
892         }
893 
getRadioGroup()894         public CharSequence getRadioGroup() {
895             return mRadioGroup;
896         }
897 
isEnabled()898         public boolean isEnabled() {
899             return mEnabled;
900         }
901 
isSelectable()902         public boolean isSelectable() {
903             return mSelectable;
904         }
905 
addInfoStatus()906         public boolean addInfoStatus() {
907             return mAddInfoStatus;
908         }
909 
isTitleItemLoading()910         public boolean isTitleItemLoading() {
911             return mTitleItemLoading;
912         }
913 
getTitleIcon()914         public IconCompat getTitleIcon() {
915             return mTitleIcon;
916         }
917 
getTitleAction()918         public SliceAction getTitleAction() {
919             return mTitleAction;
920         }
921 
getPrimaryAction()922         public SliceAction getPrimaryAction() {
923             return mPrimaryAction;
924         }
925 
getFollowupAction()926         public SliceAction getFollowupAction() {
927             return mFollowupAction;
928         }
929 
getActionId()930         public int getActionId() {
931             return mActionId;
932         }
933 
getPageId()934         public int getPageId() {
935             return mPageId;
936         }
937 
getRedirectSliceUri()938         public CharSequence getRedirectSliceUri() {
939             return mRedirectSliceUri;
940         }
941 
getTitle()942         public CharSequence getTitle() {
943             return mTitle;
944         }
945 
isTitleLoading()946         public boolean isTitleLoading() {
947             return mTitleLoading;
948         }
949 
getSubtitle()950         public CharSequence getSubtitle() {
951             return mSubtitle;
952         }
953 
isSubtitleLoading()954         public boolean isSubtitleLoading() {
955             return mSubtitleLoading;
956         }
957 
getContentDescription()958         public CharSequence getContentDescription() {
959             return mContentDescription;
960         }
961 
getLayoutDirection()962         public int getLayoutDirection() {
963             return mLayoutDirection;
964         }
965 
getInfoText()966         public CharSequence getInfoText() {
967             return mInfoTitle;
968         }
969 
getInfoTitle()970         public CharSequence getInfoTitle() {
971             return mInfoTitle;
972         }
973 
getInfoSummary()974         public CharSequence getInfoSummary() {
975             return mInfoSummary;
976         }
977 
getInfoImage()978         public IconCompat getInfoImage() {
979             return mInfoImage;
980         }
981 
getInfoTitleIcon()982         public IconCompat getInfoTitleIcon() {
983             return mInfoTitleIcon;
984         }
985 
getEndItems()986         public List<Object> getEndItems() {
987             return mEndItems;
988         }
989 
getInfoItems()990         public List<Pair<String, String>> getInfoItems() {
991             return mInfoItems;
992         }
993 
getEndTypes()994         public List<Integer> getEndTypes() {
995             return mEndTypes;
996         }
997 
getEndLoads()998         public List<Boolean> getEndLoads() {
999             return mEndLoads;
1000         }
1001 
isTitleActionLoading()1002         public boolean isTitleActionLoading() {
1003             return mTitleActionLoading;
1004         }
1005     }
1006 }
1007