1/* 2 * Copyright (C) 2014 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.content.Context; 17import android.content.res.TypedArray; 18import android.graphics.Bitmap; 19import android.graphics.Canvas; 20import android.graphics.Paint; 21import android.graphics.PorterDuff; 22import android.graphics.PorterDuffColorFilter; 23import android.graphics.drawable.BitmapDrawable; 24import android.graphics.drawable.Drawable; 25import android.support.v17.leanback.R; 26import android.support.v17.leanback.util.MathUtil; 27import android.util.TypedValue; 28import android.view.KeyEvent; 29 30/** 31 * A {@link Row} of playback controls to be displayed by a {@link PlaybackControlsRowPresenter}. 32 * 33 * This row consists of some optional item detail, a series of primary actions, 34 * and an optional series of secondary actions. 35 * 36 * <p> 37 * Controls are specified via an {@link ObjectAdapter} containing one or more 38 * {@link Action}s. 39 * </p> 40 * <p> 41 * Adapters should have their {@link PresenterSelector} set to an instance of 42 * {@link ControlButtonPresenterSelector}. 43 * </p> 44 */ 45public class PlaybackControlsRow extends Row { 46 47 /** 48 * Listener for progress or duration change. 49 */ 50 public static class OnPlaybackProgressCallback { 51 /** 52 * Called when {@link PlaybackControlsRow#getCurrentPosition()} changed. 53 * @param row The PlaybackControlsRow that current time changed. 54 * @param currentTimeMs Current time in milliseconds. 55 */ 56 public void onCurrentPositionChanged(PlaybackControlsRow row, long currentTimeMs) { 57 } 58 59 /** 60 * Called when {@link PlaybackControlsRow#getDuration()} changed. 61 * @param row The PlaybackControlsRow that total time changed. 62 * @param totalTime Total time in milliseconds. 63 */ 64 public void onDurationChanged(PlaybackControlsRow row, long totalTime) { 65 } 66 67 /** 68 * Called when {@link PlaybackControlsRow#getBufferedPosition()} changed. 69 * @param row The PlaybackControlsRow that buffered progress changed. 70 * @param bufferedProgressMs Buffered time in milliseconds. 71 */ 72 public void onBufferedPositionChanged(PlaybackControlsRow row, long bufferedProgressMs) { 73 } 74 } 75 76 /** 77 * Base class for an action comprised of a series of icons. 78 */ 79 public static abstract class MultiAction extends Action { 80 private int mIndex; 81 private Drawable[] mDrawables; 82 private String[] mLabels; 83 private String[] mLabels2; 84 85 /** 86 * Constructor 87 * @param id The id of the Action. 88 */ 89 public MultiAction(int id) { 90 super(id); 91 } 92 93 /** 94 * Sets the array of drawables. The size of the array defines the range 95 * of valid indices for this action. 96 */ 97 public void setDrawables(Drawable[] drawables) { 98 mDrawables = drawables; 99 setIndex(0); 100 } 101 102 /** 103 * Sets the array of strings used as labels. The size of the array defines the range 104 * of valid indices for this action. The labels are used to define the accessibility 105 * content description unless secondary labels are provided. 106 */ 107 public void setLabels(String[] labels) { 108 mLabels = labels; 109 setIndex(0); 110 } 111 112 /** 113 * Sets the array of strings used as secondary labels. These labels are used 114 * in place of the primary labels for accessibility content description only. 115 */ 116 public void setSecondaryLabels(String[] labels) { 117 mLabels2 = labels; 118 setIndex(0); 119 } 120 121 /** 122 * Returns the number of actions. 123 */ 124 public int getActionCount() { 125 if (mDrawables != null) { 126 return mDrawables.length; 127 } 128 if (mLabels != null) { 129 return mLabels.length; 130 } 131 return 0; 132 } 133 134 /** 135 * Returns the drawable at the given index. 136 */ 137 public Drawable getDrawable(int index) { 138 return mDrawables == null ? null : mDrawables[index]; 139 } 140 141 /** 142 * Returns the label at the given index. 143 */ 144 public String getLabel(int index) { 145 return mLabels == null ? null : mLabels[index]; 146 } 147 148 /** 149 * Returns the secondary label at the given index. 150 */ 151 public String getSecondaryLabel(int index) { 152 return mLabels2 == null ? null : mLabels2[index]; 153 } 154 155 /** 156 * Increments the index, wrapping to zero once the end is reached. 157 */ 158 public void nextIndex() { 159 setIndex(mIndex < getActionCount() - 1 ? mIndex + 1 : 0); 160 } 161 162 /** 163 * Sets the current index. 164 */ 165 public void setIndex(int index) { 166 mIndex = index; 167 if (mDrawables != null) { 168 setIcon(mDrawables[mIndex]); 169 } 170 if (mLabels != null) { 171 setLabel1(mLabels[mIndex]); 172 } 173 if (mLabels2 != null) { 174 setLabel2(mLabels2[mIndex]); 175 } 176 } 177 178 /** 179 * Returns the current index. 180 */ 181 public int getIndex() { 182 return mIndex; 183 } 184 } 185 186 /** 187 * An action displaying icons for play and pause. 188 */ 189 public static class PlayPauseAction extends MultiAction { 190 /** 191 * Action index for the play icon. 192 * @deprecated Use {@link #INDEX_PLAY} 193 */ 194 @Deprecated 195 public static int PLAY = 0; 196 197 /** 198 * Action index for the pause icon. 199 * @deprecated Use {@link #INDEX_PAUSE} 200 */ 201 @Deprecated 202 public static int PAUSE = 1; 203 204 /** 205 * Action index for the play icon. 206 */ 207 public static final int INDEX_PLAY = 0; 208 209 /** 210 * Action index for the pause icon. 211 */ 212 public static final int INDEX_PAUSE = 1; 213 214 /** 215 * Constructor 216 * @param context Context used for loading resources. 217 */ 218 public PlayPauseAction(Context context) { 219 super(R.id.lb_control_play_pause); 220 Drawable[] drawables = new Drawable[2]; 221 drawables[INDEX_PLAY] = getStyledDrawable(context, 222 R.styleable.lbPlaybackControlsActionIcons_play); 223 drawables[INDEX_PAUSE] = getStyledDrawable(context, 224 R.styleable.lbPlaybackControlsActionIcons_pause); 225 setDrawables(drawables); 226 227 String[] labels = new String[drawables.length]; 228 labels[INDEX_PLAY] = context.getString(R.string.lb_playback_controls_play); 229 labels[INDEX_PAUSE] = context.getString(R.string.lb_playback_controls_pause); 230 setLabels(labels); 231 addKeyCode(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 232 addKeyCode(KeyEvent.KEYCODE_MEDIA_PLAY); 233 addKeyCode(KeyEvent.KEYCODE_MEDIA_PAUSE); 234 } 235 } 236 237 /** 238 * An action displaying an icon for fast forward. 239 */ 240 public static class FastForwardAction extends MultiAction { 241 /** 242 * Constructor 243 * @param context Context used for loading resources. 244 */ 245 public FastForwardAction(Context context) { 246 this(context, 1); 247 } 248 249 /** 250 * Constructor 251 * @param context Context used for loading resources. 252 * @param numSpeeds Number of supported fast forward speeds. 253 */ 254 public FastForwardAction(Context context, int numSpeeds) { 255 super(R.id.lb_control_fast_forward); 256 257 if (numSpeeds < 1) { 258 throw new IllegalArgumentException("numSpeeds must be > 0"); 259 } 260 Drawable[] drawables = new Drawable[numSpeeds + 1]; 261 drawables[0] = getStyledDrawable(context, 262 R.styleable.lbPlaybackControlsActionIcons_fast_forward); 263 setDrawables(drawables); 264 265 String[] labels = new String[getActionCount()]; 266 labels[0] = context.getString(R.string.lb_playback_controls_fast_forward); 267 268 String[] labels2 = new String[getActionCount()]; 269 labels2[0] = labels[0]; 270 271 for (int i = 1; i <= numSpeeds; i++) { 272 int multiplier = i + 1; 273 labels[i] = context.getResources().getString( 274 R.string.lb_control_display_fast_forward_multiplier, multiplier); 275 labels2[i] = context.getResources().getString( 276 R.string.lb_playback_controls_fast_forward_multiplier, multiplier); 277 } 278 setLabels(labels); 279 setSecondaryLabels(labels2); 280 addKeyCode(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD); 281 } 282 } 283 284 /** 285 * An action displaying an icon for rewind. 286 */ 287 public static class RewindAction extends MultiAction { 288 /** 289 * Constructor 290 * @param context Context used for loading resources. 291 */ 292 public RewindAction(Context context) { 293 this(context, 1); 294 } 295 296 /** 297 * Constructor 298 * @param context Context used for loading resources. 299 * @param numSpeeds Number of supported fast forward speeds. 300 */ 301 public RewindAction(Context context, int numSpeeds) { 302 super(R.id.lb_control_fast_rewind); 303 304 if (numSpeeds < 1) { 305 throw new IllegalArgumentException("numSpeeds must be > 0"); 306 } 307 Drawable[] drawables = new Drawable[numSpeeds + 1]; 308 drawables[0] = getStyledDrawable(context, 309 R.styleable.lbPlaybackControlsActionIcons_rewind); 310 setDrawables(drawables); 311 312 String[] labels = new String[getActionCount()]; 313 labels[0] = context.getString(R.string.lb_playback_controls_rewind); 314 315 String[] labels2 = new String[getActionCount()]; 316 labels2[0] = labels[0]; 317 318 for (int i = 1; i <= numSpeeds; i++) { 319 int multiplier = i + 1; 320 labels[i] = labels[i] = context.getResources().getString( 321 R.string.lb_control_display_rewind_multiplier, multiplier); 322 labels2[i] = context.getResources().getString( 323 R.string.lb_playback_controls_rewind_multiplier, multiplier); 324 } 325 setLabels(labels); 326 setSecondaryLabels(labels2); 327 addKeyCode(KeyEvent.KEYCODE_MEDIA_REWIND); 328 } 329 } 330 331 /** 332 * An action displaying an icon for skip next. 333 */ 334 public static class SkipNextAction extends Action { 335 /** 336 * Constructor 337 * @param context Context used for loading resources. 338 */ 339 public SkipNextAction(Context context) { 340 super(R.id.lb_control_skip_next); 341 setIcon(getStyledDrawable(context, 342 R.styleable.lbPlaybackControlsActionIcons_skip_next)); 343 setLabel1(context.getString(R.string.lb_playback_controls_skip_next)); 344 addKeyCode(KeyEvent.KEYCODE_MEDIA_NEXT); 345 } 346 } 347 348 /** 349 * An action displaying an icon for skip previous. 350 */ 351 public static class SkipPreviousAction extends Action { 352 /** 353 * Constructor 354 * @param context Context used for loading resources. 355 */ 356 public SkipPreviousAction(Context context) { 357 super(R.id.lb_control_skip_previous); 358 setIcon(getStyledDrawable(context, 359 R.styleable.lbPlaybackControlsActionIcons_skip_previous)); 360 setLabel1(context.getString(R.string.lb_playback_controls_skip_previous)); 361 addKeyCode(KeyEvent.KEYCODE_MEDIA_PREVIOUS); 362 } 363 } 364 365 /** 366 * An action displaying an icon for picture-in-picture. 367 */ 368 public static class PictureInPictureAction extends Action { 369 /** 370 * Constructor 371 * @param context Context used for loading resources. 372 */ 373 public PictureInPictureAction(Context context) { 374 super(R.id.lb_control_picture_in_picture); 375 setIcon(getStyledDrawable(context, 376 R.styleable.lbPlaybackControlsActionIcons_picture_in_picture)); 377 setLabel1(context.getString(R.string.lb_playback_controls_picture_in_picture)); 378 addKeyCode(KeyEvent.KEYCODE_WINDOW); 379 } 380 } 381 382 /** 383 * An action displaying an icon for "more actions". 384 */ 385 public static class MoreActions extends Action { 386 /** 387 * Constructor 388 * @param context Context used for loading resources. 389 */ 390 public MoreActions(Context context) { 391 super(R.id.lb_control_more_actions); 392 setIcon(context.getResources().getDrawable(R.drawable.lb_ic_more)); 393 setLabel1(context.getString(R.string.lb_playback_controls_more_actions)); 394 } 395 } 396 397 /** 398 * A base class for displaying a thumbs action. 399 */ 400 public static abstract class ThumbsAction extends MultiAction { 401 /** 402 * Action index for the solid thumb icon. 403 * @deprecated Use {@link #INDEX_SOLID} 404 */ 405 @Deprecated 406 public static int SOLID = 0; 407 408 /** 409 * Action index for the outline thumb icon. 410 * @deprecated Use {@link #INDEX_OUTLINE} 411 */ 412 @Deprecated 413 public static int OUTLINE = 1; 414 415 /** 416 * Action index for the solid thumb icon. 417 */ 418 public static final int INDEX_SOLID = 0; 419 420 /** 421 * Action index for the outline thumb icon. 422 */ 423 public static final int INDEX_OUTLINE = 1; 424 425 /** 426 * Constructor 427 * @param context Context used for loading resources. 428 */ 429 public ThumbsAction(int id, Context context, int solidIconIndex, int outlineIconIndex) { 430 super(id); 431 Drawable[] drawables = new Drawable[2]; 432 drawables[INDEX_SOLID] = getStyledDrawable(context, solidIconIndex); 433 drawables[INDEX_OUTLINE] = getStyledDrawable(context, outlineIconIndex); 434 setDrawables(drawables); 435 } 436 } 437 438 /** 439 * An action displaying an icon for thumbs up. 440 */ 441 public static class ThumbsUpAction extends ThumbsAction { 442 public ThumbsUpAction(Context context) { 443 super(R.id.lb_control_thumbs_up, context, 444 R.styleable.lbPlaybackControlsActionIcons_thumb_up, 445 R.styleable.lbPlaybackControlsActionIcons_thumb_up_outline); 446 String[] labels = new String[getActionCount()]; 447 labels[INDEX_SOLID] = context.getString(R.string.lb_playback_controls_thumb_up); 448 labels[INDEX_OUTLINE] = context.getString( 449 R.string.lb_playback_controls_thumb_up_outline); 450 setLabels(labels); 451 } 452 } 453 454 /** 455 * An action displaying an icon for thumbs down. 456 */ 457 public static class ThumbsDownAction extends ThumbsAction { 458 public ThumbsDownAction(Context context) { 459 super(R.id.lb_control_thumbs_down, context, 460 R.styleable.lbPlaybackControlsActionIcons_thumb_down, 461 R.styleable.lbPlaybackControlsActionIcons_thumb_down_outline); 462 String[] labels = new String[getActionCount()]; 463 labels[INDEX_SOLID] = context.getString(R.string.lb_playback_controls_thumb_down); 464 labels[INDEX_OUTLINE] = context.getString( 465 R.string.lb_playback_controls_thumb_down_outline); 466 setLabels(labels); 467 } 468 } 469 470 /** 471 * An action for displaying three repeat states: none, one, or all. 472 */ 473 public static class RepeatAction extends MultiAction { 474 /** 475 * Action index for the repeat-none icon. 476 * @deprecated Use {@link #INDEX_NONE} 477 */ 478 @Deprecated 479 public static int NONE = 0; 480 481 /** 482 * Action index for the repeat-all icon. 483 * @deprecated Use {@link #INDEX_ALL} 484 */ 485 @Deprecated 486 public static int ALL = 1; 487 488 /** 489 * Action index for the repeat-one icon. 490 * @deprecated Use {@link #INDEX_ONE} 491 */ 492 @Deprecated 493 public static int ONE = 2; 494 495 /** 496 * Action index for the repeat-none icon. 497 */ 498 public static final int INDEX_NONE = 0; 499 500 /** 501 * Action index for the repeat-all icon. 502 */ 503 public static final int INDEX_ALL = 1; 504 505 /** 506 * Action index for the repeat-one icon. 507 */ 508 public static final int INDEX_ONE = 2; 509 510 /** 511 * Constructor 512 * @param context Context used for loading resources. 513 */ 514 public RepeatAction(Context context) { 515 this(context, getIconHighlightColor(context)); 516 } 517 518 /** 519 * Constructor 520 * @param context Context used for loading resources 521 * @param highlightColor Color to display the repeat-all and repeat0one icons. 522 */ 523 public RepeatAction(Context context, int highlightColor) { 524 this(context, highlightColor, highlightColor); 525 } 526 527 /** 528 * Constructor 529 * @param context Context used for loading resources 530 * @param repeatAllColor Color to display the repeat-all icon. 531 * @param repeatOneColor Color to display the repeat-one icon. 532 */ 533 public RepeatAction(Context context, int repeatAllColor, int repeatOneColor) { 534 super(R.id.lb_control_repeat); 535 Drawable[] drawables = new Drawable[3]; 536 BitmapDrawable repeatDrawable = (BitmapDrawable) getStyledDrawable(context, 537 R.styleable.lbPlaybackControlsActionIcons_repeat); 538 BitmapDrawable repeatOneDrawable = (BitmapDrawable) getStyledDrawable(context, 539 R.styleable.lbPlaybackControlsActionIcons_repeat_one); 540 drawables[INDEX_NONE] = repeatDrawable; 541 drawables[INDEX_ALL] = repeatDrawable == null ? null 542 : new BitmapDrawable(context.getResources(), 543 createBitmap(repeatDrawable.getBitmap(), repeatAllColor)); 544 drawables[INDEX_ONE] = repeatOneDrawable == null ? null 545 : new BitmapDrawable(context.getResources(), 546 createBitmap(repeatOneDrawable.getBitmap(), repeatOneColor)); 547 setDrawables(drawables); 548 549 String[] labels = new String[drawables.length]; 550 // Note, labels denote the action taken when clicked 551 labels[INDEX_NONE] = context.getString(R.string.lb_playback_controls_repeat_all); 552 labels[INDEX_ALL] = context.getString(R.string.lb_playback_controls_repeat_one); 553 labels[INDEX_ONE] = context.getString(R.string.lb_playback_controls_repeat_none); 554 setLabels(labels); 555 } 556 } 557 558 /** 559 * An action for displaying a shuffle icon. 560 */ 561 public static class ShuffleAction extends MultiAction { 562 /** 563 * Action index for shuffle is off. 564 * @deprecated Use {@link #INDEX_OFF} 565 */ 566 @Deprecated 567 public static int OFF = 0; 568 569 /** 570 * Action index for shuffle is on. 571 * @deprecated Use {@link #INDEX_ON} 572 */ 573 @Deprecated 574 public static int ON = 1; 575 576 /** 577 * Action index for shuffle is off 578 */ 579 public static final int INDEX_OFF = 0; 580 581 /** 582 * Action index for shuffle is on. 583 */ 584 public static final int INDEX_ON = 1; 585 586 /** 587 * Constructor 588 * @param context Context used for loading resources. 589 */ 590 public ShuffleAction(Context context) { 591 this(context, getIconHighlightColor(context)); 592 } 593 594 /** 595 * Constructor 596 * @param context Context used for loading resources. 597 * @param highlightColor Color for the highlighted icon state. 598 */ 599 public ShuffleAction(Context context, int highlightColor) { 600 super(R.id.lb_control_shuffle); 601 BitmapDrawable uncoloredDrawable = (BitmapDrawable) getStyledDrawable(context, 602 R.styleable.lbPlaybackControlsActionIcons_shuffle); 603 Drawable[] drawables = new Drawable[2]; 604 drawables[INDEX_OFF] = uncoloredDrawable; 605 drawables[INDEX_ON] = new BitmapDrawable(context.getResources(), 606 createBitmap(uncoloredDrawable.getBitmap(), highlightColor)); 607 setDrawables(drawables); 608 609 String[] labels = new String[drawables.length]; 610 labels[INDEX_OFF] = context.getString(R.string.lb_playback_controls_shuffle_enable); 611 labels[INDEX_ON] = context.getString(R.string.lb_playback_controls_shuffle_disable); 612 setLabels(labels); 613 } 614 } 615 616 /** 617 * An action for displaying a HQ (High Quality) icon. 618 */ 619 public static class HighQualityAction extends MultiAction { 620 /** 621 * Action index for high quality is off. 622 * @deprecated Use {@link #INDEX_OFF} 623 */ 624 @Deprecated 625 public static int OFF = 0; 626 627 /** 628 * Action index for high quality is on. 629 * @deprecated Use {@link #INDEX_ON} 630 */ 631 @Deprecated 632 public static int ON = 1; 633 634 /** 635 * Action index for high quality is off. 636 */ 637 public static final int INDEX_OFF = 0; 638 639 /** 640 * Action index for high quality is on. 641 */ 642 public static final int INDEX_ON = 1; 643 644 /** 645 * Constructor 646 * @param context Context used for loading resources. 647 */ 648 public HighQualityAction(Context context) { 649 this(context, getIconHighlightColor(context)); 650 } 651 652 /** 653 * Constructor 654 * @param context Context used for loading resources. 655 * @param highlightColor Color for the highlighted icon state. 656 */ 657 public HighQualityAction(Context context, int highlightColor) { 658 super(R.id.lb_control_high_quality); 659 BitmapDrawable uncoloredDrawable = (BitmapDrawable) getStyledDrawable(context, 660 R.styleable.lbPlaybackControlsActionIcons_high_quality); 661 Drawable[] drawables = new Drawable[2]; 662 drawables[INDEX_OFF] = uncoloredDrawable; 663 drawables[INDEX_ON] = new BitmapDrawable(context.getResources(), 664 createBitmap(uncoloredDrawable.getBitmap(), highlightColor)); 665 setDrawables(drawables); 666 667 String[] labels = new String[drawables.length]; 668 labels[INDEX_OFF] = context.getString( 669 R.string.lb_playback_controls_high_quality_enable); 670 labels[INDEX_ON] = context.getString( 671 R.string.lb_playback_controls_high_quality_disable); 672 setLabels(labels); 673 } 674 } 675 676 /** 677 * An action for displaying a CC (Closed Captioning) icon. 678 */ 679 public static class ClosedCaptioningAction extends MultiAction { 680 /** 681 * Action index for closed caption is off. 682 * @deprecated Use {@link #INDEX_OFF} 683 */ 684 @Deprecated 685 public static int OFF = 0; 686 687 /** 688 * Action index for closed caption is on. 689 * @deprecated Use {@link #INDEX_ON} 690 */ 691 @Deprecated 692 public static int ON = 1; 693 694 /** 695 * Action index for closed caption is off. 696 */ 697 public static final int INDEX_OFF = 0; 698 699 /** 700 * Action index for closed caption is on. 701 */ 702 public static final int INDEX_ON = 1; 703 704 705 /** 706 * Constructor 707 * @param context Context used for loading resources. 708 */ 709 public ClosedCaptioningAction(Context context) { 710 this(context, getIconHighlightColor(context)); 711 } 712 713 /** 714 * Constructor 715 * @param context Context used for loading resources. 716 * @param highlightColor Color for the highlighted icon state. 717 */ 718 public ClosedCaptioningAction(Context context, int highlightColor) { 719 super(R.id.lb_control_closed_captioning); 720 BitmapDrawable uncoloredDrawable = (BitmapDrawable) getStyledDrawable(context, 721 R.styleable.lbPlaybackControlsActionIcons_closed_captioning); 722 Drawable[] drawables = new Drawable[2]; 723 drawables[INDEX_OFF] = uncoloredDrawable; 724 drawables[INDEX_ON] = new BitmapDrawable(context.getResources(), 725 createBitmap(uncoloredDrawable.getBitmap(), highlightColor)); 726 setDrawables(drawables); 727 728 String[] labels = new String[drawables.length]; 729 labels[INDEX_OFF] = context.getString( 730 R.string.lb_playback_controls_closed_captioning_enable); 731 labels[INDEX_ON] = context.getString( 732 R.string.lb_playback_controls_closed_captioning_disable); 733 setLabels(labels); 734 } 735 } 736 737 static Bitmap createBitmap(Bitmap bitmap, int color) { 738 Bitmap dst = bitmap.copy(bitmap.getConfig(), true); 739 Canvas canvas = new Canvas(dst); 740 Paint paint = new Paint(); 741 paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)); 742 canvas.drawBitmap(bitmap, 0, 0, paint); 743 return dst; 744 } 745 746 static int getIconHighlightColor(Context context) { 747 TypedValue outValue = new TypedValue(); 748 if (context.getTheme().resolveAttribute(R.attr.playbackControlsIconHighlightColor, 749 outValue, true)) { 750 return outValue.data; 751 } 752 return context.getResources().getColor(R.color.lb_playback_icon_highlight_no_theme); 753 } 754 755 static Drawable getStyledDrawable(Context context, int index) { 756 TypedValue outValue = new TypedValue(); 757 if (!context.getTheme().resolveAttribute( 758 R.attr.playbackControlsActionIcons, outValue, false)) { 759 return null; 760 } 761 TypedArray array = context.getTheme().obtainStyledAttributes(outValue.data, 762 R.styleable.lbPlaybackControlsActionIcons); 763 Drawable drawable = array.getDrawable(index); 764 array.recycle(); 765 return drawable; 766 } 767 768 private Object mItem; 769 private Drawable mImageDrawable; 770 private ObjectAdapter mPrimaryActionsAdapter; 771 private ObjectAdapter mSecondaryActionsAdapter; 772 private long mTotalTimeMs; 773 private long mCurrentTimeMs; 774 private long mBufferedProgressMs; 775 private OnPlaybackProgressCallback mListener; 776 777 /** 778 * Constructor for a PlaybackControlsRow that displays some details from 779 * the given item. 780 * 781 * @param item The main item for the row. 782 */ 783 public PlaybackControlsRow(Object item) { 784 mItem = item; 785 } 786 787 /** 788 * Constructor for a PlaybackControlsRow that has no item details. 789 */ 790 public PlaybackControlsRow() { 791 } 792 793 /** 794 * Returns the main item for the details page. 795 */ 796 public final Object getItem() { 797 return mItem; 798 } 799 800 /** 801 * Sets a {link @Drawable} image for this row. 802 * <p>If set after the row has been bound to a view, the adapter must be notified that 803 * this row has changed.</p> 804 * 805 * @param drawable The drawable to set. 806 */ 807 public final void setImageDrawable(Drawable drawable) { 808 mImageDrawable = drawable; 809 } 810 811 /** 812 * Sets a {@link Bitmap} for this row. 813 * <p>If set after the row has been bound to a view, the adapter must be notified that 814 * this row has changed.</p> 815 * 816 * @param context The context to retrieve display metrics from. 817 * @param bm The bitmap to set. 818 */ 819 public final void setImageBitmap(Context context, Bitmap bm) { 820 mImageDrawable = new BitmapDrawable(context.getResources(), bm); 821 } 822 823 /** 824 * Returns the image {@link Drawable} of this row. 825 * 826 * @return The overview's image drawable, or null if no drawable has been 827 * assigned. 828 */ 829 public final Drawable getImageDrawable() { 830 return mImageDrawable; 831 } 832 833 /** 834 * Sets the primary actions {@link ObjectAdapter}. 835 * <p>If set after the row has been bound to a view, the adapter must be notified that 836 * this row has changed.</p> 837 */ 838 public final void setPrimaryActionsAdapter(ObjectAdapter adapter) { 839 mPrimaryActionsAdapter = adapter; 840 } 841 842 /** 843 * Sets the secondary actions {@link ObjectAdapter}. 844 * <p>If set after the row has been bound to a view, the adapter must be notified that 845 * this row has changed.</p> 846 */ 847 public final void setSecondaryActionsAdapter(ObjectAdapter adapter) { 848 mSecondaryActionsAdapter = adapter; 849 } 850 851 /** 852 * Returns the primary actions {@link ObjectAdapter}. 853 */ 854 public final ObjectAdapter getPrimaryActionsAdapter() { 855 return mPrimaryActionsAdapter; 856 } 857 858 /** 859 * Returns the secondary actions {@link ObjectAdapter}. 860 */ 861 public final ObjectAdapter getSecondaryActionsAdapter() { 862 return mSecondaryActionsAdapter; 863 } 864 865 /** 866 * Sets the total time in milliseconds for the playback controls row. 867 * <p>If set after the row has been bound to a view, the adapter must be notified that 868 * this row has changed.</p> 869 * @deprecated Use {@link #setDuration(long)} 870 */ 871 @Deprecated 872 public void setTotalTime(int ms) { 873 setDuration((long) ms); 874 } 875 876 /** 877 * Sets the total time in milliseconds (long type) for the playback controls row. 878 * @param ms Total time in milliseconds of long type. 879 * @deprecated Use {@link #setDuration(long)} 880 */ 881 @Deprecated 882 public void setTotalTimeLong(long ms) { 883 setDuration(ms); 884 } 885 886 /** 887 * Sets the total time in milliseconds (long type) for the playback controls row. 888 * If this row is bound to a view, the view will automatically 889 * be updated to reflect the new value. 890 * @param ms Total time in milliseconds of long type. 891 */ 892 public void setDuration(long ms) { 893 if (mTotalTimeMs != ms) { 894 mTotalTimeMs = ms; 895 if (mListener != null) { 896 mListener.onDurationChanged(this, mTotalTimeMs); 897 } 898 } 899 } 900 901 /** 902 * Returns the total time in milliseconds for the playback controls row. 903 * @throws ArithmeticException If total time in milliseconds overflows int. 904 * @deprecated use {@link #getDuration()} 905 */ 906 @Deprecated 907 public int getTotalTime() { 908 return MathUtil.safeLongToInt(getTotalTimeLong()); 909 } 910 911 /** 912 * Returns the total time in milliseconds of long type for the playback controls row. 913 * @deprecated use {@link #getDuration()} 914 */ 915 @Deprecated 916 public long getTotalTimeLong() { 917 return mTotalTimeMs; 918 } 919 920 /** 921 * Returns duration in milliseconds. 922 * @return Duration in milliseconds. 923 */ 924 public long getDuration() { 925 return mTotalTimeMs; 926 } 927 928 /** 929 * Sets the current time in milliseconds for the playback controls row. 930 * If this row is bound to a view, the view will automatically 931 * be updated to reflect the new value. 932 * @deprecated use {@link #setCurrentPosition(long)} 933 */ 934 @Deprecated 935 public void setCurrentTime(int ms) { 936 setCurrentTimeLong((long) ms); 937 } 938 939 /** 940 * Sets the current time in milliseconds for playback controls row in long type. 941 * @param ms Current time in milliseconds of long type. 942 * @deprecated use {@link #setCurrentPosition(long)} 943 */ 944 @Deprecated 945 public void setCurrentTimeLong(long ms) { 946 setCurrentPosition(ms); 947 } 948 949 /** 950 * Sets the current time in milliseconds for the playback controls row. 951 * If this row is bound to a view, the view will automatically 952 * be updated to reflect the new value. 953 * @param ms Current time in milliseconds of long type. 954 */ 955 public void setCurrentPosition(long ms) { 956 if (mCurrentTimeMs != ms) { 957 mCurrentTimeMs = ms; 958 if (mListener != null) { 959 mListener.onCurrentPositionChanged(this, mCurrentTimeMs); 960 } 961 } 962 } 963 964 /** 965 * Returns the current time in milliseconds for the playback controls row. 966 * @throws ArithmeticException If current time in milliseconds overflows int. 967 * @deprecated Use {@link #getCurrentPosition()} 968 */ 969 @Deprecated 970 public int getCurrentTime() { 971 return MathUtil.safeLongToInt(getCurrentTimeLong()); 972 } 973 974 /** 975 * Returns the current time in milliseconds of long type for playback controls row. 976 * @deprecated Use {@link #getCurrentPosition()} 977 */ 978 @Deprecated 979 public long getCurrentTimeLong() { 980 return mCurrentTimeMs; 981 } 982 983 /** 984 * Returns the current time in milliseconds of long type for playback controls row. 985 */ 986 public long getCurrentPosition() { 987 return mCurrentTimeMs; 988 } 989 990 /** 991 * Sets the buffered progress for the playback controls row. 992 * If this row is bound to a view, the view will automatically 993 * be updated to reflect the new value. 994 * @deprecated Use {@link #setBufferedPosition(long)} 995 */ 996 @Deprecated 997 public void setBufferedProgress(int ms) { 998 setBufferedPosition((long) ms); 999 } 1000 1001 /** 1002 * Sets the buffered progress for the playback controls row. 1003 * @param ms Buffered progress in milliseconds of long type. 1004 * @deprecated Use {@link #setBufferedPosition(long)} 1005 */ 1006 @Deprecated 1007 public void setBufferedProgressLong(long ms) { 1008 setBufferedPosition(ms); 1009 } 1010 1011 /** 1012 * Sets the buffered progress for the playback controls row. 1013 * @param ms Buffered progress in milliseconds of long type. 1014 */ 1015 public void setBufferedPosition(long ms) { 1016 if (mBufferedProgressMs != ms) { 1017 mBufferedProgressMs = ms; 1018 if (mListener != null) { 1019 mListener.onBufferedPositionChanged(this, mBufferedProgressMs); 1020 } 1021 } 1022 } 1023 /** 1024 * Returns the buffered progress for the playback controls row. 1025 * @throws ArithmeticException If buffered progress in milliseconds overflows int. 1026 * @deprecated Use {@link #getBufferedPosition()} 1027 */ 1028 @Deprecated 1029 public int getBufferedProgress() { 1030 return MathUtil.safeLongToInt(getBufferedPosition()); 1031 } 1032 1033 /** 1034 * Returns the buffered progress of long type for the playback controls row. 1035 * @deprecated Use {@link #getBufferedPosition()} 1036 */ 1037 @Deprecated 1038 public long getBufferedProgressLong() { 1039 return mBufferedProgressMs; 1040 } 1041 1042 /** 1043 * Returns the buffered progress of long type for the playback controls row. 1044 */ 1045 public long getBufferedPosition() { 1046 return mBufferedProgressMs; 1047 } 1048 1049 /** 1050 * Returns the Action associated with the given keycode, or null if no associated action exists. 1051 * Searches the primary adapter first, then the secondary adapter. 1052 */ 1053 public Action getActionForKeyCode(int keyCode) { 1054 Action action = getActionForKeyCode(getPrimaryActionsAdapter(), keyCode); 1055 if (action != null) { 1056 return action; 1057 } 1058 return getActionForKeyCode(getSecondaryActionsAdapter(), keyCode); 1059 } 1060 1061 /** 1062 * Returns the Action associated with the given keycode, or null if no associated action exists. 1063 */ 1064 public Action getActionForKeyCode(ObjectAdapter adapter, int keyCode) { 1065 if (adapter != mPrimaryActionsAdapter && adapter != mSecondaryActionsAdapter) { 1066 throw new IllegalArgumentException("Invalid adapter"); 1067 } 1068 for (int i = 0; i < adapter.size(); i++) { 1069 Action action = (Action) adapter.get(i); 1070 if (action.respondsToKeyCode(keyCode)) { 1071 return action; 1072 } 1073 } 1074 return null; 1075 } 1076 1077 /** 1078 * Sets a listener to be called when the playback state changes. 1079 */ 1080 public void setOnPlaybackProgressChangedListener(OnPlaybackProgressCallback listener) { 1081 mListener = listener; 1082 } 1083} 1084