GuidedAction.java revision be6eb618b4ba8a74d69fa04c77c717b1fcbea818
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.v17.leanback.R; 17 18import android.content.Context; 19import android.content.Intent; 20import android.graphics.drawable.Drawable; 21import android.text.InputType; 22import android.util.Log; 23 24import java.util.List; 25 26/** 27 * A data class which represents an action within a {@link 28 * android.support.v17.leanback.app.GuidedStepFragment}. GuidedActions contain at minimum a title 29 * and a description, and typically also an icon. 30 * <p> 31 * A GuidedAction typically represents a single action a user may take, but may also represent a 32 * possible choice out of a group of mutually exclusive choices (similar to radio buttons), or an 33 * information-only label (in which case the item cannot be clicked). 34 * <p> 35 * GuidedActions may optionally be checked. They may also indicate that they will request further 36 * user input on selection, in which case they will be displayed with a chevron indicator. 37 */ 38public class GuidedAction extends Action { 39 40 private static final String TAG = "GuidedAction"; 41 42 /** 43 * Special check set Id that is neither checkbox nor radio. 44 */ 45 public static final int NO_CHECK_SET = 0; 46 /** 47 * Default checkset Id for radio. 48 */ 49 public static final int DEFAULT_CHECK_SET_ID = 1; 50 /** 51 * Checkset Id for checkbox. 52 */ 53 public static final int CHECKBOX_CHECK_SET_ID = -1; 54 55 /** 56 * When finishing editing, goes to next action. 57 */ 58 public static final long ACTION_ID_NEXT = -2; 59 /** 60 * When finishing editing, stay on current action. 61 */ 62 public static final long ACTION_ID_CURRENT = -3; 63 64 /** 65 * Id of standard OK action. 66 */ 67 public static final long ACTION_ID_OK = -4; 68 69 /** 70 * Id of standard Cancel action. 71 */ 72 public static final long ACTION_ID_CANCEL = -5; 73 74 /** 75 * Id of standard Finish action. 76 */ 77 public static final long ACTION_ID_FINISH = -6; 78 79 /** 80 * Id of standard Finish action. 81 */ 82 public static final long ACTION_ID_CONTINUE = -7; 83 84 /** 85 * Id of standard Yes action. 86 */ 87 public static final long ACTION_ID_YES = -8; 88 89 /** 90 * Id of standard No action. 91 */ 92 public static final long ACTION_ID_NO = -9; 93 94 /** 95 * Builds a {@link GuidedAction} object. When subclass GuidedAction, you may override this 96 * Builder class and call {@link #applyValues(GuidedAction)}. 97 */ 98 public static class Builder { 99 private long mId; 100 private CharSequence mTitle; 101 private CharSequence mEditTitle; 102 private CharSequence mDescription; 103 private CharSequence mEditDescription; 104 private Drawable mIcon; 105 private boolean mChecked; 106 private boolean mMultilineDescription; 107 private boolean mHasNext; 108 private boolean mInfoOnly; 109 private boolean mEditable = false; 110 private boolean mDescriptionEditable = false; 111 private int mInputType = InputType.TYPE_CLASS_TEXT; 112 private int mDescriptionInputType = InputType.TYPE_CLASS_TEXT; 113 private int mEditInputType = InputType.TYPE_CLASS_TEXT; 114 private int mDescriptionEditInputType = InputType.TYPE_CLASS_TEXT; 115 private int mCheckSetId = NO_CHECK_SET; 116 private boolean mEnabled = true; 117 private boolean mFocusable = true; 118 private List<GuidedAction> mSubActions; 119 private Intent mIntent; 120 121 /** 122 * Builds the GuidedAction corresponding to this Builder. 123 * @return the GuidedAction as configured through this Builder. 124 */ 125 public final GuidedAction build() { 126 GuidedAction action = new GuidedAction(); 127 applyValues(action); 128 return action; 129 } 130 131 /** 132 * Subclass Builder may call this function to apply values. 133 * @param action GuidedAction to apply Builder values. 134 */ 135 protected final void applyValues(GuidedAction action) { 136 // Base Action values 137 action.setId(mId); 138 action.setLabel1(mTitle); 139 action.setEditTitle(mEditTitle); 140 action.setLabel2(mDescription); 141 action.setEditDescription(mEditDescription); 142 action.setIcon(mIcon); 143 144 // Subclass values 145 action.mIntent = mIntent; 146 action.mEditable = mEditable; 147 action.mDescriptionEditable = mDescriptionEditable; 148 action.mInputType = mInputType; 149 action.mDescriptionInputType = mDescriptionInputType; 150 action.mEditInputType = mEditInputType; 151 action.mDescriptionEditInputType = mDescriptionEditInputType; 152 action.mChecked = mChecked; 153 action.mCheckSetId = mCheckSetId; 154 action.mMultilineDescription = mMultilineDescription; 155 action.mHasNext = mHasNext; 156 action.mInfoOnly = mInfoOnly; 157 action.mEnabled = mEnabled; 158 action.mFocusable = mFocusable; 159 action.mSubActions = mSubActions; 160 } 161 162 /** 163 * Construct a standard "OK" action with {@link GuidedAction#ACTION_ID_OK}. 164 * @param context Context for loading action title. 165 * @return The same Builder object. 166 */ 167 public Builder constructOK(Context context) { 168 mId = ACTION_ID_OK; 169 mTitle = context.getString(android.R.string.ok); 170 return this; 171 } 172 173 /** 174 * Construct a standard "Cancel" action with {@link GuidedAction#ACTION_ID_CANCEL}. 175 * @param context Context for loading action title. 176 * @return The same Builder object. 177 */ 178 public Builder constructCancel(Context context) { 179 mId = ACTION_ID_CANCEL; 180 mTitle = context.getString(android.R.string.cancel); 181 return this; 182 } 183 184 /** 185 * Construct a standard "Finish" action with {@link GuidedAction#ACTION_ID_FINISH}. 186 * @param context Context for loading action title. 187 * @return The same Builder object. 188 */ 189 public Builder constructFinish(Context context) { 190 mId = ACTION_ID_FINISH; 191 mTitle = context.getString(R.string.lb_guidedaction_finish_title); 192 return this; 193 } 194 195 /** 196 * Construct a standard "Continue" action with {@link GuidedAction#ACTION_ID_CONTINUE}. 197 * @param context Context for loading action title. 198 * @return The same Builder object. 199 */ 200 public Builder constructContinue(Context context) { 201 mId = ACTION_ID_CONTINUE; 202 mHasNext = true; 203 mTitle = context.getString(R.string.lb_guidedaction_continue_title); 204 return this; 205 } 206 207 /** 208 * Construct a standard "Yes" action with {@link GuidedAction#ACTION_ID_YES}. 209 * @param context Context for loading action title. 210 * @return The same Builder object. 211 */ 212 public Builder constructYes(Context context) { 213 mId = ACTION_ID_YES; 214 mTitle = context.getString(android.R.string.yes); 215 return this; 216 } 217 218 /** 219 * Construct a standard "No" action with {@link GuidedAction#ACTION_ID_NO}. 220 * @param context Context for loading action title. 221 * @return The same Builder object. 222 */ 223 public Builder constructNo(Context context) { 224 mId = ACTION_ID_NO; 225 mTitle = context.getString(android.R.string.no); 226 return this; 227 } 228 229 /** 230 * Sets the ID associated with this action. The ID can be any value the client wishes; 231 * it is typically used to determine what to do when an action is clicked. 232 * @param id The ID to associate with this action. 233 */ 234 public Builder id(long id) { 235 mId = id; 236 return this; 237 } 238 239 /** 240 * Sets the title for this action. The title is typically a short string indicating the 241 * action to be taken on click, e.g. "Continue" or "Cancel". 242 * @param title The title for this action. 243 */ 244 public Builder title(CharSequence title) { 245 mTitle = title; 246 return this; 247 } 248 249 /** 250 * Sets the optional title text to edit. When TextView is activated, the edit title 251 * replaces the string of title. 252 */ 253 public Builder editTitle(CharSequence editTitle) { 254 mEditTitle = editTitle; 255 return this; 256 } 257 258 /** 259 * Sets the description for this action. The description is typically a longer string 260 * providing extra information on what the action will do. 261 * @param description The description for this action. 262 */ 263 public Builder description(CharSequence description) { 264 mDescription = description; 265 return this; 266 } 267 268 /** 269 * Sets the optional description text to edit. When TextView is activated, the edit 270 * description replaces the string of description. 271 * @param description The description to edit for this action. 272 */ 273 public Builder editDescription(CharSequence description) { 274 mEditDescription = description; 275 return this; 276 } 277 278 /** 279 * Sets the intent associated with this action. Clients would typically fire this intent 280 * directly when the action is clicked. 281 * @param intent The intent associated with this action. 282 */ 283 public Builder intent(Intent intent) { 284 mIntent = intent; 285 return this; 286 } 287 288 /** 289 * Sets the action's icon drawable. 290 * @param icon The drawable for the icon associated with this action. 291 */ 292 public Builder icon(Drawable icon) { 293 mIcon = icon; 294 return this; 295 } 296 297 /** 298 * Sets the action's icon drawable by retrieving it by resource ID from the specified 299 * context. This is a convenience function that simply looks up the drawable and calls 300 * {@link #icon}. 301 * @param iconResourceId The resource ID for the icon associated with this action. 302 * @param context The context whose resource ID should be retrieved. 303 */ 304 public Builder iconResourceId(int iconResourceId, Context context) { 305 return icon(context.getResources().getDrawable(iconResourceId)); 306 } 307 308 /** 309 * Indicates whether this action title is editable. Note: Editable actions cannot also be 310 * checked, or belong to a check set. 311 * @param editable Whether this action is editable. 312 */ 313 public Builder editable(boolean editable) { 314 mEditable = editable; 315 if (mChecked || mCheckSetId != NO_CHECK_SET) { 316 throw new IllegalArgumentException("Editable actions cannot also be checked"); 317 } 318 return this; 319 } 320 321 /** 322 * Indicates whether this action's description is editable 323 * @param editable Whether this action description is editable. 324 */ 325 public Builder descriptionEditable(boolean editable) { 326 mDescriptionEditable = editable; 327 if (mChecked || mCheckSetId != NO_CHECK_SET) { 328 throw new IllegalArgumentException("Editable actions cannot also be checked"); 329 } 330 return this; 331 } 332 333 /** 334 * Sets {@link InputType} of this action title not in editing. 335 * 336 * @param inputType InputType for the action title not in editing. 337 */ 338 public Builder inputType(int inputType) { 339 mInputType = inputType; 340 return this; 341 } 342 343 /** 344 * Sets {@link InputType} of this action description not in editing. 345 * 346 * @param inputType InputType for the action description not in editing. 347 */ 348 public Builder descriptionInputType(int inputType) { 349 mDescriptionInputType = inputType; 350 return this; 351 } 352 353 354 /** 355 * Sets {@link InputType} of this action title in editing. 356 * 357 * @param inputType InputType for the action title in editing. 358 */ 359 public Builder editInputType(int inputType) { 360 mEditInputType = inputType; 361 return this; 362 } 363 364 /** 365 * Sets {@link InputType} of this action description in editing. 366 * 367 * @param inputType InputType for the action description in editing. 368 */ 369 public Builder descriptionEditInputType(int inputType) { 370 mDescriptionEditInputType = inputType; 371 return this; 372 } 373 374 375 /** 376 * Indicates whether this action is initially checked. 377 * @param checked Whether this action is checked. 378 */ 379 public Builder checked(boolean checked) { 380 mChecked = checked; 381 if (mEditable || mDescriptionEditable) { 382 throw new IllegalArgumentException("Editable actions cannot also be checked"); 383 } 384 return this; 385 } 386 387 /** 388 * Indicates whether this action is part of a single-select group similar to radio buttons 389 * or this action is a checkbox. When one item in a check set is checked, all others with 390 * the same check set ID will be nchecked automatically. 391 * @param checkSetId The check set ID, or {@link GuidedAction#NO_CHECK_SET} to indicate not 392 * radio or checkbox, or {@link GuidedAction#CHECKBOX_CHECK_SET_ID} to indicate a checkbox. 393 */ 394 public Builder checkSetId(int checkSetId) { 395 mCheckSetId = checkSetId; 396 if (mEditable || mDescriptionEditable) { 397 throw new IllegalArgumentException("Editable actions cannot also be in check sets"); 398 } 399 return this; 400 } 401 402 /** 403 * Indicates whether the title and description are long, and should be displayed 404 * appropriately. 405 * @param multilineDescription Whether this action has a multiline description. 406 */ 407 public Builder multilineDescription(boolean multilineDescription) { 408 mMultilineDescription = multilineDescription; 409 return this; 410 } 411 412 /** 413 * Indicates whether this action has a next state and should display a chevron. 414 * @param hasNext Whether this action has a next state. 415 */ 416 public Builder hasNext(boolean hasNext) { 417 mHasNext = hasNext; 418 return this; 419 } 420 421 /** 422 * Indicates whether this action is for information purposes only and cannot be clicked. 423 * @param infoOnly Whether this action has a next state. 424 */ 425 public Builder infoOnly(boolean infoOnly) { 426 mInfoOnly = infoOnly; 427 return this; 428 } 429 430 /** 431 * Indicates whether this action is enabled. If not enabled, an action cannot be clicked. 432 * @param enabled Whether the action is enabled. 433 */ 434 public Builder enabled(boolean enabled) { 435 mEnabled = enabled; 436 return this; 437 } 438 439 /** 440 * Indicates whether this action can take focus. 441 * @param focusable 442 * @return The same Builder object. 443 */ 444 public Builder focusable(boolean focusable) { 445 mFocusable = focusable; 446 return this; 447 } 448 449 /** 450 * Sets sub actions list. 451 * @param subActions 452 * @return The same Builder object. 453 */ 454 public Builder subActions(List<GuidedAction> subActions) { 455 mSubActions = subActions; 456 return this; 457 } 458 } 459 460 private CharSequence mEditTitle; 461 private CharSequence mEditDescription; 462 private boolean mEditable; 463 private boolean mDescriptionEditable; 464 private int mInputType; 465 private int mDescriptionInputType; 466 private int mEditInputType; 467 private int mDescriptionEditInputType; 468 private boolean mMultilineDescription; 469 private boolean mHasNext; 470 private boolean mChecked; 471 private boolean mInfoOnly; 472 private int mCheckSetId; 473 private boolean mEnabled; 474 private boolean mFocusable; 475 private List<GuidedAction> mSubActions; 476 477 private Intent mIntent; 478 479 protected GuidedAction() { 480 super(0); 481 } 482 483 /** 484 * Returns the title of this action. 485 * @return The title set when this action was built. 486 */ 487 public CharSequence getTitle() { 488 return getLabel1(); 489 } 490 491 /** 492 * Sets the title of this action. 493 * @param title The title set when this action was built. 494 */ 495 public void setTitle(CharSequence title) { 496 setLabel1(title); 497 } 498 499 /** 500 * Returns the optional title text to edit. When not null, it is being edited instead of 501 * {@link #getTitle()}. 502 * @return Optional title text to edit instead of {@link #getTitle()}. 503 */ 504 public CharSequence getEditTitle() { 505 return mEditTitle; 506 } 507 508 /** 509 * Sets the optional title text to edit instead of {@link #setTitle(CharSequence)}. 510 * @param editTitle Optional title text to edit instead of {@link #setTitle(CharSequence)}. 511 */ 512 public void setEditTitle(CharSequence editTitle) { 513 mEditTitle = editTitle; 514 } 515 516 /** 517 * Returns the optional description text to edit. When not null, it is being edited instead of 518 * {@link #getDescription()}. 519 * @return Optional description text to edit instead of {@link #getDescription()}. 520 */ 521 public CharSequence getEditDescription() { 522 return mEditDescription; 523 } 524 525 /** 526 * Sets the optional description text to edit instead of {@link #setDescription(CharSequence)}. 527 * @param editDescription Optional description text to edit instead of 528 * {@link #setDescription(CharSequence)}. 529 */ 530 public void setEditDescription(CharSequence editDescription) { 531 mEditDescription = editDescription; 532 } 533 534 /** 535 * Returns true if {@link #getEditTitle()} is not null. When true, the {@link #getEditTitle()} 536 * is being edited instead of {@link #getTitle()}. 537 * @return true if {@link #getEditTitle()} is not null. 538 */ 539 public boolean isEditTitleUsed() { 540 return mEditTitle != null; 541 } 542 543 /** 544 * Returns the description of this action. 545 * @return The description of this action. 546 */ 547 public CharSequence getDescription() { 548 return getLabel2(); 549 } 550 551 /** 552 * Sets the description of this action. 553 * @param description The description of the action. 554 */ 555 public void setDescription(CharSequence description) { 556 setLabel2(description); 557 } 558 559 /** 560 * Returns the intent associated with this action. 561 * @return The intent set when this action was built. 562 */ 563 public Intent getIntent() { 564 return mIntent; 565 } 566 567 /** 568 * Returns whether this action title is editable. 569 * @return true if the action title is editable, false otherwise. 570 */ 571 public boolean isEditable() { 572 return mEditable; 573 } 574 575 /** 576 * Returns whether this action description is editable. 577 * @return true if the action description is editable, false otherwise. 578 */ 579 public boolean isDescriptionEditable() { 580 return mDescriptionEditable; 581 } 582 583 /** 584 * Returns InputType of action title in editing; only valid when {@link #isEditable()} is true. 585 * @return InputType of action title in editing. 586 */ 587 public int getEditInputType() { 588 return mEditInputType; 589 } 590 591 /** 592 * Returns InputType of action description in editing; only valid when 593 * {@link #isDescriptionEditable()} is true. 594 * @return InputType of action description in editing. 595 */ 596 public int getDescriptionEditInputType() { 597 return mDescriptionEditInputType; 598 } 599 600 /** 601 * Returns InputType of action title not in editing. 602 * @return InputType of action title not in editing. 603 */ 604 public int getInputType() { 605 return mInputType; 606 } 607 608 /** 609 * Returns InputType of action description not in editing. 610 * @return InputType of action description not in editing. 611 */ 612 public int getDescriptionInputType() { 613 return mDescriptionInputType; 614 } 615 616 /** 617 * Returns whether this action is checked. 618 * @return true if the action is currently checked, false otherwise. 619 */ 620 public boolean isChecked() { 621 return mChecked; 622 } 623 624 /** 625 * Sets whether this action is checked. 626 * @param checked Whether this action should be checked. 627 */ 628 public void setChecked(boolean checked) { 629 mChecked = checked; 630 } 631 632 /** 633 * Returns the check set id this action is a part of. All actions in the same list with the same 634 * check set id are considered linked. When one of the actions within that set is selected, that 635 * action becomes checked, while all the other actions become unchecked. 636 * 637 * @return an integer representing the check set this action is a part of, or 638 * {@link #CHECKBOX_CHECK_SET_ID} if this is a checkbox, or {@link #NO_CHECK_SET} if 639 * this action is not a checkbox or radiobutton. 640 */ 641 public int getCheckSetId() { 642 return mCheckSetId; 643 } 644 645 /** 646 * Returns whether this action is has a multiline description. 647 * @return true if the action was constructed as having a multiline description, false 648 * otherwise. 649 */ 650 public boolean hasMultilineDescription() { 651 return mMultilineDescription; 652 } 653 654 /** 655 * Returns whether this action is enabled. 656 * @return true if the action is currently enabled, false otherwise. 657 */ 658 public boolean isEnabled() { 659 return mEnabled; 660 } 661 662 /** 663 * Sets whether this action is enabled. 664 * @param enabled Whether this action should be enabled. 665 */ 666 public void setEnabled(boolean enabled) { 667 mEnabled = enabled; 668 } 669 670 /** 671 * Returns whether this action is focusable. 672 * @return true if the action is currently focusable, false otherwise. 673 */ 674 public boolean isFocusable() { 675 return mFocusable; 676 } 677 678 /** 679 * Sets whether this action is focusable. 680 * @param focusable Whether this action should be focusable. 681 */ 682 public void setFocusable(boolean focusable) { 683 mFocusable = focusable; 684 } 685 686 /** 687 * Returns whether this action will request further user input when selected, such as showing 688 * another GuidedStepFragment or launching a new activity. Configured during construction. 689 * @return true if the action will request further user input when selected, false otherwise. 690 */ 691 public boolean hasNext() { 692 return mHasNext; 693 } 694 695 /** 696 * Returns whether the action will only display information and is thus not clickable. If both 697 * this and {@link #hasNext()} are true, infoOnly takes precedence. The default is false. For 698 * example, this might represent e.g. the amount of storage a document uses, or the cost of an 699 * app. 700 * @return true if will only display information, false otherwise. 701 */ 702 public boolean infoOnly() { 703 return mInfoOnly; 704 } 705 706 /** 707 * Change sub actions list. 708 * @param actions Sub actions list to set on this action. Sets null to disable sub actions. 709 */ 710 public void setSubActions(List<GuidedAction> actions) { 711 mSubActions = actions; 712 } 713 714 /** 715 * @return List of sub actions or null if sub actions list is not enabled. 716 */ 717 public List<GuidedAction> getSubActions() { 718 return mSubActions; 719 } 720 721 /** 722 * @return True if has sub actions list, even it's currently empty. 723 */ 724 public boolean hasSubActions() { 725 return mSubActions != null; 726 } 727 728} 729