GuidedAction.java revision accd54788b769d62a99300306741551fe207b2d4
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14package android.support.v17.leanback.widget;
15
16import android.support.annotation.DrawableRes;
17import android.support.annotation.StringRes;
18import android.support.v17.leanback.R;
19import android.support.v4.content.ContextCompat;
20
21import android.content.Context;
22import android.content.Intent;
23import android.graphics.drawable.Drawable;
24import android.text.InputType;
25
26import java.util.List;
27
28/**
29 * A data class which represents an action within a {@link
30 * android.support.v17.leanback.app.GuidedStepFragment}. GuidedActions contain at minimum a title
31 * and a description, and typically also an icon.
32 * <p>
33 * A GuidedAction typically represents a single action a user may take, but may also represent a
34 * possible choice out of a group of mutually exclusive choices (similar to radio buttons), or an
35 * information-only label (in which case the item cannot be clicked).
36 * <p>
37 * GuidedActions may optionally be checked. They may also indicate that they will request further
38 * user input on selection, in which case they will be displayed with a chevron indicator.
39 * <p>
40 * GuidedAction recommends to use {@link Builder}. When application subclass GuidedAction, it
41 * can subclass {@link BuilderBase}, implement its own builder() method where it should
42 * call {@link BuilderBase#applyValues(GuidedAction)}.
43 */
44public class GuidedAction extends Action {
45
46    private static final String TAG = "GuidedAction";
47
48    /**
49     * Special check set Id that is neither checkbox nor radio.
50     */
51    public static final int NO_CHECK_SET = 0;
52    /**
53     * Default checkset Id for radio.
54     */
55    public static final int DEFAULT_CHECK_SET_ID = 1;
56    /**
57     * Checkset Id for checkbox.
58     */
59    public static final int CHECKBOX_CHECK_SET_ID = -1;
60
61    /**
62     * When finishing editing, goes to next action.
63     */
64    public static final long ACTION_ID_NEXT = -2;
65    /**
66     * When finishing editing, stay on current action.
67     */
68    public static final long ACTION_ID_CURRENT = -3;
69
70    /**
71     * Id of standard OK action.
72     */
73    public static final long ACTION_ID_OK = -4;
74
75    /**
76     * Id of standard Cancel action.
77     */
78    public static final long ACTION_ID_CANCEL = -5;
79
80    /**
81     * Id of standard Finish action.
82     */
83    public static final long ACTION_ID_FINISH = -6;
84
85    /**
86     * Id of standard Finish action.
87     */
88    public static final long ACTION_ID_CONTINUE = -7;
89
90    /**
91     * Id of standard Yes action.
92     */
93    public static final long ACTION_ID_YES = -8;
94
95    /**
96     * Id of standard No action.
97     */
98    public static final long ACTION_ID_NO = -9;
99
100    static final int EDITING_NONE = 0;
101    static final int EDITING_TITLE = 1;
102    static final int EDITING_DESCRIPTION = 2;
103    static final int EDITING_ACTIVATOR_VIEW = 3;
104
105    /**
106     * Base builder class to build a {@link GuidedAction} object.  When subclass GuidedAction, you
107     * can override this BuilderBase class, implements your build() method which should call
108     * {@link #applyValues(GuidedAction)}.  When using GuidedAction directly, use {@link Builder}.
109     */
110    public abstract static class BuilderBase<B extends BuilderBase> {
111        private Context mContext;
112        private long mId;
113        private CharSequence mTitle;
114        private CharSequence mEditTitle;
115        private CharSequence mDescription;
116        private CharSequence mEditDescription;
117        private Drawable mIcon;
118        /**
119         * The mActionFlags holds various action states such as whether title or description are
120         * editable, or the action is focusable.
121         *
122         */
123        private int mActionFlags;
124
125        private int mEditable = EDITING_NONE;
126        private int mInputType = InputType.TYPE_CLASS_TEXT;
127        private int mDescriptionInputType = InputType.TYPE_CLASS_TEXT;
128        private int mEditInputType = InputType.TYPE_CLASS_TEXT;
129        private int mDescriptionEditInputType = InputType.TYPE_CLASS_TEXT;
130        private int mCheckSetId = NO_CHECK_SET;
131        private List<GuidedAction> mSubActions;
132        private Intent mIntent;
133
134        /**
135         * Creates a BuilderBase for GuidedAction or its subclass.
136         * @param context Context object used to build the GuidedAction.
137         */
138        public BuilderBase(Context context) {
139            mContext = context;
140            mActionFlags = PF_ENABLED | PF_FOCUSABLE;
141        }
142
143        /**
144         * Returns Context of this Builder.
145         * @return Context of this Builder.
146         */
147        public Context getContext() {
148            return mContext;
149        }
150
151        private void setFlags(int flag, int mask) {
152            mActionFlags = (mActionFlags & ~mask) | (flag & mask);
153        }
154
155        /**
156         * Subclass of BuilderBase should call this function to apply values.
157         * @param action GuidedAction to apply BuilderBase values.
158         */
159        protected final void applyValues(GuidedAction action) {
160            // Base Action values
161            action.setId(mId);
162            action.setLabel1(mTitle);
163            action.setEditTitle(mEditTitle);
164            action.setLabel2(mDescription);
165            action.setEditDescription(mEditDescription);
166            action.setIcon(mIcon);
167
168            // Subclass values
169            action.mIntent = mIntent;
170            action.mEditable = mEditable;
171            action.mInputType = mInputType;
172            action.mDescriptionInputType = mDescriptionInputType;
173            action.mEditInputType = mEditInputType;
174            action.mDescriptionEditInputType = mDescriptionEditInputType;
175            action.mActionFlags = mActionFlags;
176            action.mCheckSetId = mCheckSetId;
177            action.mSubActions = mSubActions;
178        }
179
180        /**
181         * Construct a clickable action with associated id and auto assign pre-defined title for the
182         * action. If the id is not supported, the method simply does nothing.
183         * @param id One of {@link GuidedAction#ACTION_ID_OK} {@link GuidedAction#ACTION_ID_CANCEL}
184         * {@link GuidedAction#ACTION_ID_FINISH} {@link GuidedAction#ACTION_ID_CONTINUE}
185         * {@link GuidedAction#ACTION_ID_YES} {@link GuidedAction#ACTION_ID_NO}.
186         * @return The same BuilderBase object.
187         */
188        public B clickAction(long id) {
189            if (id == ACTION_ID_OK) {
190                mId = ACTION_ID_OK;
191                mTitle = mContext.getString(android.R.string.ok);
192            } else if (id == ACTION_ID_CANCEL) {
193                mId = ACTION_ID_CANCEL;
194                mTitle = mContext.getString(android.R.string.cancel);
195            } else if (id == ACTION_ID_FINISH) {
196                mId = ACTION_ID_FINISH;
197                mTitle = mContext.getString(R.string.lb_guidedaction_finish_title);
198            } else if (id == ACTION_ID_CONTINUE) {
199                mId = ACTION_ID_CONTINUE;
200                mTitle = mContext.getString(R.string.lb_guidedaction_continue_title);
201            } else if (id == ACTION_ID_YES) {
202                mId = ACTION_ID_YES;
203                mTitle = mContext.getString(android.R.string.yes);
204            } else if (id == ACTION_ID_NO) {
205                mId = ACTION_ID_NO;
206                mTitle = mContext.getString(android.R.string.no);
207            }
208            return (B) this;
209        }
210
211        /**
212         * Sets the ID associated with this action.  The ID can be any value the client wishes;
213         * it is typically used to determine what to do when an action is clicked.
214         * @param id The ID to associate with this action.
215         */
216        public B id(long id) {
217            mId = id;
218            return (B) this;
219        }
220
221        /**
222         * Sets the title for this action.  The title is typically a short string indicating the
223         * action to be taken on click, e.g. "Continue" or "Cancel".
224         * @param title The title for this action.
225         */
226        public B title(CharSequence title) {
227            mTitle = title;
228            return (B) this;
229        }
230
231        /**
232         * Sets the title for this action.  The title is typically a short string indicating the
233         * action to be taken on click, e.g. "Continue" or "Cancel".
234         * @param titleResourceId The resource id of title for this action.
235         */
236        public B title(@StringRes int titleResourceId) {
237            mTitle = getContext().getString(titleResourceId);
238            return (B) this;
239        }
240
241        /**
242         * Sets the optional title text to edit.  When TextView is activated, the edit title
243         * replaces the string of title.
244         * @param editTitle The optional title text to edit when TextView is activated.
245         */
246        public B editTitle(CharSequence editTitle) {
247            mEditTitle = editTitle;
248            return (B) this;
249        }
250
251        /**
252         * Sets the optional title text to edit.  When TextView is activated, the edit title
253         * replaces the string of title.
254         * @param editTitleResourceId String resource id of the optional title text to edit when
255         * TextView is activated.
256         */
257        public B editTitle(@StringRes int editTitleResourceId) {
258            mEditTitle = getContext().getString(editTitleResourceId);
259            return (B) this;
260        }
261
262        /**
263         * Sets the description for this action.  The description is typically a longer string
264         * providing extra information on what the action will do.
265         * @param description The description for this action.
266         */
267        public B description(CharSequence description) {
268            mDescription = description;
269            return (B) this;
270        }
271
272        /**
273         * Sets the description for this action.  The description is typically a longer string
274         * providing extra information on what the action will do.
275         * @param descriptionResourceId String resource id of the description for this action.
276         */
277        public B description(@StringRes int descriptionResourceId) {
278            mDescription = getContext().getString(descriptionResourceId);
279            return (B) this;
280        }
281
282        /**
283         * Sets the optional description text to edit.  When TextView is activated, the edit
284         * description replaces the string of description.
285         * @param description The description to edit for this action.
286         */
287        public B editDescription(CharSequence description) {
288            mEditDescription = description;
289            return (B) this;
290        }
291
292        /**
293         * Sets the optional description text to edit.  When TextView is activated, the edit
294         * description replaces the string of description.
295         * @param descriptionResourceId String resource id of the description to edit for this
296         * action.
297         */
298        public B editDescription(@StringRes int descriptionResourceId) {
299            mEditDescription = getContext().getString(descriptionResourceId);
300            return (B) this;
301        }
302
303        /**
304         * Sets the intent associated with this action.  Clients would typically fire this intent
305         * directly when the action is clicked.
306         * @param intent The intent associated with this action.
307         */
308        public B intent(Intent intent) {
309            mIntent = intent;
310            return (B) this;
311        }
312
313        /**
314         * Sets the action's icon drawable.
315         * @param icon The drawable for the icon associated with this action.
316         */
317        public B icon(Drawable icon) {
318            mIcon = icon;
319            return (B) this;
320        }
321
322        /**
323         * Sets the action's icon drawable by retrieving it by resource ID from the specified
324         * context. This is a convenience function that simply looks up the drawable and calls
325         * {@link #icon(Drawable)}.
326         * @param iconResourceId The resource ID for the icon associated with this action.
327         * @param context The context whose resource ID should be retrieved.
328         * @deprecated Use {@link #icon(int)}.
329         */
330        @Deprecated
331        public B iconResourceId(@DrawableRes int iconResourceId, Context context) {
332            return icon(ContextCompat.getDrawable(context, iconResourceId));
333        }
334
335        /**
336         * Sets the action's icon drawable by retrieving it by resource ID from Builder's
337         * context. This is a convenience function that simply looks up the drawable and calls
338         * {@link #icon(Drawable)}.
339         * @param iconResourceId The resource ID for the icon associated with this action.
340         */
341        public B icon(@DrawableRes int iconResourceId) {
342            return icon(ContextCompat.getDrawable(getContext(), iconResourceId));
343        }
344
345        /**
346         * Indicates whether this action title is editable. Note: Editable actions cannot also be
347         * checked, or belong to a check set.
348         * @param editable Whether this action is editable.
349         */
350        public B editable(boolean editable) {
351            if (!editable) {
352                if (mEditable == EDITING_TITLE) {
353                    mEditable = EDITING_NONE;
354                }
355                return (B) this;
356            }
357            mEditable = EDITING_TITLE;
358            if (isChecked() || mCheckSetId != NO_CHECK_SET) {
359                throw new IllegalArgumentException("Editable actions cannot also be checked");
360            }
361            return (B) this;
362        }
363
364        /**
365         * Indicates whether this action's description is editable
366         * @param editable Whether this action description is editable.
367         */
368        public B descriptionEditable(boolean editable) {
369            if (!editable) {
370                if (mEditable == EDITING_DESCRIPTION) {
371                    mEditable = EDITING_NONE;
372                }
373                return (B) this;
374            }
375            mEditable = EDITING_DESCRIPTION;
376            if (isChecked() || mCheckSetId != NO_CHECK_SET) {
377                throw new IllegalArgumentException("Editable actions cannot also be checked");
378            }
379            return (B) this;
380        }
381
382        /**
383         * Indicates whether this action has a view can be activated to edit, e.g. a DatePicker.
384         * @param editable Whether this action has view can be activated to edit.
385         */
386        public B hasEditableActivatorView(boolean editable) {
387            if (!editable) {
388                if (mEditable == EDITING_ACTIVATOR_VIEW) {
389                    mEditable = EDITING_NONE;
390                }
391                return (B) this;
392            }
393            mEditable = EDITING_ACTIVATOR_VIEW;
394            if (isChecked() || mCheckSetId != NO_CHECK_SET) {
395                throw new IllegalArgumentException("Editable actions cannot also be checked");
396            }
397            return (B) this;
398        }
399
400        /**
401         * Sets {@link InputType} of this action title not in editing.
402         *
403         * @param inputType InputType for the action title not in editing.
404         */
405        public B inputType(int inputType) {
406            mInputType = inputType;
407            return (B) this;
408        }
409
410        /**
411         * Sets {@link InputType} of this action description not in editing.
412         *
413         * @param inputType InputType for the action description not in editing.
414         */
415        public B descriptionInputType(int inputType) {
416            mDescriptionInputType = inputType;
417            return (B) this;
418        }
419
420
421        /**
422         * Sets {@link InputType} of this action title in editing.
423         *
424         * @param inputType InputType for the action title in editing.
425         */
426        public B editInputType(int inputType) {
427            mEditInputType = inputType;
428            return (B) this;
429        }
430
431        /**
432         * Sets {@link InputType} of this action description in editing.
433         *
434         * @param inputType InputType for the action description in editing.
435         */
436        public B descriptionEditInputType(int inputType) {
437            mDescriptionEditInputType = inputType;
438            return (B) this;
439        }
440
441
442        private boolean isChecked() {
443            return (mActionFlags & PF_CHECKED) == PF_CHECKED;
444        }
445        /**
446         * Indicates whether this action is initially checked.
447         * @param checked Whether this action is checked.
448         */
449        public B checked(boolean checked) {
450            setFlags(checked ? PF_CHECKED : 0, PF_CHECKED);
451            if (mEditable != EDITING_NONE) {
452                throw new IllegalArgumentException("Editable actions cannot also be checked");
453            }
454            return (B) this;
455        }
456
457        /**
458         * Indicates whether this action is part of a single-select group similar to radio buttons
459         * or this action is a checkbox. When one item in a check set is checked, all others with
460         * the same check set ID will be checked automatically.
461         * @param checkSetId The check set ID, or {@link GuidedAction#NO_CHECK_SET} to indicate not
462         * radio or checkbox, or {@link GuidedAction#CHECKBOX_CHECK_SET_ID} to indicate a checkbox.
463         */
464        public B checkSetId(int checkSetId) {
465            mCheckSetId = checkSetId;
466            if (mEditable != EDITING_NONE) {
467                throw new IllegalArgumentException("Editable actions cannot also be in check sets");
468            }
469            return (B) this;
470        }
471
472        /**
473         * Indicates whether the title and description are long, and should be displayed
474         * appropriately.
475         * @param multilineDescription Whether this action has a multiline description.
476         */
477        public B multilineDescription(boolean multilineDescription) {
478            setFlags(multilineDescription ? PF_MULTI_lINE_DESCRIPTION : 0,
479                    PF_MULTI_lINE_DESCRIPTION);
480            return (B) this;
481        }
482
483        /**
484         * Indicates whether this action has a next state and should display a chevron.
485         * @param hasNext Whether this action has a next state.
486         */
487        public B hasNext(boolean hasNext) {
488            setFlags(hasNext ? PF_HAS_NEXT : 0, PF_HAS_NEXT);
489            return (B) this;
490        }
491
492        /**
493         * Indicates whether this action is for information purposes only and cannot be clicked.
494         * @param infoOnly Whether this action has a next state.
495         */
496        public B infoOnly(boolean infoOnly) {
497            setFlags(infoOnly ? PF_INFO_ONLY : 0, PF_INFO_ONLY);
498            return (B) this;
499        }
500
501        /**
502         * Indicates whether this action is enabled.  If not enabled, an action cannot be clicked.
503         * @param enabled Whether the action is enabled.
504         */
505        public B enabled(boolean enabled) {
506            setFlags(enabled ? PF_ENABLED : 0, PF_ENABLED);
507            return (B) this;
508        }
509
510        /**
511         * Indicates whether this action can take focus.
512         * @param focusable
513         * @return The same BuilderBase object.
514         */
515        public B focusable(boolean focusable) {
516            setFlags(focusable ? PF_FOCUSABLE : 0, PF_FOCUSABLE);
517            return (B) this;
518        }
519
520        /**
521         * Sets sub actions list.
522         * @param subActions
523         * @return The same BuilderBase object.
524         */
525        public B subActions(List<GuidedAction> subActions) {
526            mSubActions = subActions;
527            return (B) this;
528        }
529    }
530
531    /**
532     * Builds a {@link GuidedAction} object.
533     */
534    public static class Builder extends BuilderBase<Builder> {
535
536        /**
537         * @deprecated Use {@link GuidedAction.Builder#GuidedAction.Builder(Context)}.
538         */
539        @Deprecated
540        public Builder() {
541            super(null);
542        }
543
544        /**
545         * Creates a Builder for GuidedAction.
546         * @param context Context to build GuidedAction.
547         */
548        public Builder(Context context) {
549            super(context);
550        }
551
552        /**
553         * Builds the GuidedAction corresponding to this Builder.
554         * @return The GuidedAction as configured through this Builder.
555         */
556        public GuidedAction build() {
557            GuidedAction action = new GuidedAction();
558            applyValues(action);
559            return action;
560        }
561
562    }
563
564    private static final int PF_CHECKED = 0x00000001;
565    private static final int PF_MULTI_lINE_DESCRIPTION = 0x00000002;
566    private static final int PF_HAS_NEXT = 0x00000004;
567    private static final int PF_INFO_ONLY = 0x00000008;
568    private static final int PF_ENABLED = 0x00000010;
569    private static final int PF_FOCUSABLE = 0x00000020;
570    private int mActionFlags;
571
572    private CharSequence mEditTitle;
573    private CharSequence mEditDescription;
574    private int mEditable;
575    private int mInputType;
576    private int mDescriptionInputType;
577    private int mEditInputType;
578    private int mDescriptionEditInputType;
579
580    private int mCheckSetId;
581
582    private List<GuidedAction> mSubActions;
583
584    private Intent mIntent;
585
586    protected GuidedAction() {
587        super(0);
588    }
589
590    private void setFlags(int flag, int mask) {
591        mActionFlags = (mActionFlags & ~mask) | (flag & mask);
592    }
593
594    /**
595     * Returns the title of this action.
596     * @return The title set when this action was built.
597     */
598    public CharSequence getTitle() {
599        return getLabel1();
600    }
601
602    /**
603     * Sets the title of this action.
604     * @param title The title set when this action was built.
605     */
606    public void setTitle(CharSequence title) {
607        setLabel1(title);
608    }
609
610    /**
611     * Returns the optional title text to edit.  When not null, it is being edited instead of
612     * {@link #getTitle()}.
613     * @return Optional title text to edit instead of {@link #getTitle()}.
614     */
615    public CharSequence getEditTitle() {
616        return mEditTitle;
617    }
618
619    /**
620     * Sets the optional title text to edit instead of {@link #setTitle(CharSequence)}.
621     * @param editTitle Optional title text to edit instead of {@link #setTitle(CharSequence)}.
622     */
623    public void setEditTitle(CharSequence editTitle) {
624        mEditTitle = editTitle;
625    }
626
627    /**
628     * Returns the optional description text to edit.  When not null, it is being edited instead of
629     * {@link #getDescription()}.
630     * @return Optional description text to edit instead of {@link #getDescription()}.
631     */
632    public CharSequence getEditDescription() {
633        return mEditDescription;
634    }
635
636    /**
637     * Sets the optional description text to edit instead of {@link #setDescription(CharSequence)}.
638     * @param editDescription Optional description text to edit instead of
639     * {@link #setDescription(CharSequence)}.
640     */
641    public void setEditDescription(CharSequence editDescription) {
642        mEditDescription = editDescription;
643    }
644
645    /**
646     * Returns true if {@link #getEditTitle()} is not null.  When true, the {@link #getEditTitle()}
647     * is being edited instead of {@link #getTitle()}.
648     * @return true if {@link #getEditTitle()} is not null.
649     */
650    public boolean isEditTitleUsed() {
651        return mEditTitle != null;
652    }
653
654    /**
655     * Returns the description of this action.
656     * @return The description of this action.
657     */
658    public CharSequence getDescription() {
659        return getLabel2();
660    }
661
662    /**
663     * Sets the description of this action.
664     * @param description The description of the action.
665     */
666    public void setDescription(CharSequence description) {
667        setLabel2(description);
668    }
669
670    /**
671     * Returns the intent associated with this action.
672     * @return The intent set when this action was built.
673     */
674    public Intent getIntent() {
675        return mIntent;
676    }
677
678    /**
679     * Sets the intent of this action.
680     * @param intent New intent to set on this action.
681     */
682    public void setIntent(Intent intent) {
683        mIntent = intent;
684    }
685
686    /**
687     * Returns whether this action title is editable.
688     * @return true if the action title is editable, false otherwise.
689     */
690    public boolean isEditable() {
691        return mEditable == EDITING_TITLE;
692    }
693
694    /**
695     * Returns whether this action description is editable.
696     * @return true if the action description is editable, false otherwise.
697     */
698    public boolean isDescriptionEditable() {
699        return mEditable == EDITING_DESCRIPTION;
700    }
701
702    /**
703     * Returns if this action has editable title or editable description.
704     * @return True if this action has editable title or editable description, false otherwise.
705     */
706    public boolean hasTextEditable() {
707        return mEditable == EDITING_TITLE || mEditable == EDITING_DESCRIPTION;
708    }
709
710    /**
711     * Returns whether this action can be activated to edit, e.g. a DatePicker.
712     * @return true if the action can be activated to edit.
713     */
714    public boolean hasEditableActivatorView() {
715        return mEditable == EDITING_ACTIVATOR_VIEW;
716    }
717
718    /**
719     * Returns InputType of action title in editing; only valid when {@link #isEditable()} is true.
720     * @return InputType of action title in editing.
721     */
722    public int getEditInputType() {
723        return mEditInputType;
724    }
725
726    /**
727     * Returns InputType of action description in editing; only valid when
728     * {@link #isDescriptionEditable()} is true.
729     * @return InputType of action description in editing.
730     */
731    public int getDescriptionEditInputType() {
732        return mDescriptionEditInputType;
733    }
734
735    /**
736     * Returns InputType of action title not in editing.
737     * @return InputType of action title not in editing.
738     */
739    public int getInputType() {
740        return mInputType;
741    }
742
743    /**
744     * Returns InputType of action description not in editing.
745     * @return InputType of action description not in editing.
746     */
747    public int getDescriptionInputType() {
748        return mDescriptionInputType;
749    }
750
751    /**
752     * Returns whether this action is checked.
753     * @return true if the action is currently checked, false otherwise.
754     */
755    public boolean isChecked() {
756        return (mActionFlags & PF_CHECKED) == PF_CHECKED;
757    }
758
759    /**
760     * Sets whether this action is checked.
761     * @param checked Whether this action should be checked.
762     */
763    public void setChecked(boolean checked) {
764        setFlags(checked ? PF_CHECKED : 0, PF_CHECKED);
765    }
766
767    /**
768     * Returns the check set id this action is a part of. All actions in the same list with the same
769     * check set id are considered linked. When one of the actions within that set is selected, that
770     * action becomes checked, while all the other actions become unchecked.
771     *
772     * @return an integer representing the check set this action is a part of, or
773     *         {@link #CHECKBOX_CHECK_SET_ID} if this is a checkbox, or {@link #NO_CHECK_SET} if
774     *         this action is not a checkbox or radiobutton.
775     */
776    public int getCheckSetId() {
777        return mCheckSetId;
778    }
779
780    /**
781     * Returns whether this action is has a multiline description.
782     * @return true if the action was constructed as having a multiline description, false
783     * otherwise.
784     */
785    public boolean hasMultilineDescription() {
786        return (mActionFlags & PF_MULTI_lINE_DESCRIPTION) == PF_MULTI_lINE_DESCRIPTION;
787    }
788
789    /**
790     * Returns whether this action is enabled.
791     * @return true if the action is currently enabled, false otherwise.
792     */
793    public boolean isEnabled() {
794        return (mActionFlags & PF_ENABLED) == PF_ENABLED;
795    }
796
797    /**
798     * Sets whether this action is enabled.
799     * @param enabled Whether this action should be enabled.
800     */
801    public void setEnabled(boolean enabled) {
802        setFlags(enabled ? PF_ENABLED : 0, PF_ENABLED);
803    }
804
805    /**
806     * Returns whether this action is focusable.
807     * @return true if the action is currently focusable, false otherwise.
808     */
809    public boolean isFocusable() {
810        return (mActionFlags & PF_FOCUSABLE) == PF_FOCUSABLE;
811    }
812
813    /**
814     * Sets whether this action is focusable.
815     * @param focusable Whether this action should be focusable.
816     */
817    public void setFocusable(boolean focusable) {
818        setFlags(focusable ? PF_FOCUSABLE : 0, PF_FOCUSABLE);
819    }
820
821    /**
822     * Returns whether this action will request further user input when selected, such as showing
823     * another GuidedStepFragment or launching a new activity. Configured during construction.
824     * @return true if the action will request further user input when selected, false otherwise.
825     */
826    public boolean hasNext() {
827        return (mActionFlags & PF_HAS_NEXT) == PF_HAS_NEXT;
828    }
829
830    /**
831     * Returns whether the action will only display information and is thus not clickable. If both
832     * this and {@link #hasNext()} are true, infoOnly takes precedence. The default is false. For
833     * example, this might represent e.g. the amount of storage a document uses, or the cost of an
834     * app.
835     * @return true if will only display information, false otherwise.
836     */
837    public boolean infoOnly() {
838        return (mActionFlags & PF_INFO_ONLY) == PF_INFO_ONLY;
839    }
840
841    /**
842     * Change sub actions list.
843     * @param actions Sub actions list to set on this action.  Sets null to disable sub actions.
844     */
845    public void setSubActions(List<GuidedAction> actions) {
846        mSubActions = actions;
847    }
848
849    /**
850     * @return List of sub actions or null if sub actions list is not enabled.
851     */
852    public List<GuidedAction> getSubActions() {
853        return mSubActions;
854    }
855
856    /**
857     * @return True if has sub actions list, even it's currently empty.
858     */
859    public boolean hasSubActions() {
860        return mSubActions != null;
861    }
862
863}
864