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