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 */ 14 package android.support.v17.leanback.widget; 15 16 import android.support.v17.leanback.R; 17 import android.util.TypedValue; 18 import android.content.Context; 19 import android.content.res.TypedArray; 20 import android.graphics.Bitmap; 21 import android.graphics.BitmapFactory; 22 import android.graphics.Canvas; 23 import android.graphics.Color; 24 import android.graphics.Paint; 25 import android.graphics.PorterDuff; 26 import android.graphics.PorterDuffColorFilter; 27 import android.graphics.drawable.BitmapDrawable; 28 import android.graphics.drawable.Drawable; 29 import android.view.KeyEvent; 30 31 /** 32 * A {@link Row} of playback controls to be displayed by a {@link PlaybackControlsRowPresenter}. 33 * 34 * This row consists of some optional item detail, a series of primary actions, 35 * and an optional series of secondary actions. 36 * 37 * <p> 38 * Controls are specified via an {@link ObjectAdapter} containing one or more 39 * {@link Action}s. 40 * </p> 41 * <p> 42 * Adapters should have their {@link PresenterSelector} set to an instance of 43 * {@link ControlButtonPresenterSelector}. 44 * </p> 45 */ 46 public class PlaybackControlsRow extends Row { 47 48 /** 49 * Base class for an action comprised of a series of icons. 50 */ 51 public static abstract class MultiAction extends Action { 52 private int mIndex; 53 private Drawable[] mDrawables; 54 private String[] mLabels; 55 private String[] mLabels2; 56 57 /** 58 * Constructor 59 * @param id The id of the Action. 60 */ MultiAction(int id)61 public MultiAction(int id) { 62 super(id); 63 } 64 65 /** 66 * Sets the array of drawables. The size of the array defines the range 67 * of valid indices for this action. 68 */ setDrawables(Drawable[] drawables)69 public void setDrawables(Drawable[] drawables) { 70 mDrawables = drawables; 71 setIndex(0); 72 } 73 74 /** 75 * Sets the array of strings used as labels. The size of the array defines the range 76 * of valid indices for this action. The labels are used to define the accessibility 77 * content description unless secondary labels are provided. 78 */ setLabels(String[] labels)79 public void setLabels(String[] labels) { 80 mLabels = labels; 81 setIndex(0); 82 } 83 84 /** 85 * Sets the array of strings used as secondary labels. These labels are used 86 * in place of the primary labels for accessibility content description only. 87 */ setSecondaryLabels(String[] labels)88 public void setSecondaryLabels(String[] labels) { 89 mLabels2 = labels; 90 setIndex(0); 91 } 92 93 /** 94 * Returns the number of actions. 95 */ getActionCount()96 public int getActionCount() { 97 if (mDrawables != null) { 98 return mDrawables.length; 99 } 100 if (mLabels != null) { 101 return mLabels.length; 102 } 103 return 0; 104 } 105 106 /** 107 * Returns the drawable at the given index. 108 */ getDrawable(int index)109 public Drawable getDrawable(int index) { 110 return mDrawables == null ? null : mDrawables[index]; 111 } 112 113 /** 114 * Returns the label at the given index. 115 */ getLabel(int index)116 public String getLabel(int index) { 117 return mLabels == null ? null : mLabels[index]; 118 } 119 120 /** 121 * Returns the secondary label at the given index. 122 */ getSecondaryLabel(int index)123 public String getSecondaryLabel(int index) { 124 return mLabels2 == null ? null : mLabels2[index]; 125 } 126 127 /** 128 * Increments the index, wrapping to zero once the end is reached. 129 */ nextIndex()130 public void nextIndex() { 131 setIndex(mIndex < getActionCount() - 1 ? mIndex + 1 : 0); 132 } 133 134 /** 135 * Sets the current index. 136 */ 137 public void setIndex(int index) { 138 mIndex = index; 139 if (mDrawables != null) { 140 setIcon(mDrawables[mIndex]); 141 } 142 if (mLabels != null) { 143 setLabel1(mLabels[mIndex]); 144 } 145 if (mLabels2 != null) { 146 setLabel2(mLabels2[mIndex]); 147 } 148 } 149 150 /** 151 * Returns the current index. 152 */ 153 public int getIndex() { 154 return mIndex; 155 } 156 } 157 158 /** 159 * An action displaying icons for play and pause. 160 */ 161 public static class PlayPauseAction extends MultiAction { 162 /** 163 * Action index for the play icon. 164 */ 165 public static int PLAY = 0; 166 167 /** 168 * Action index for the pause icon. 169 */ 170 public static int PAUSE = 1; 171 172 /** 173 * Constructor 174 * @param context Context used for loading resources. 175 */ 176 public PlayPauseAction(Context context) { 177 super(R.id.lb_control_play_pause); 178 Drawable[] drawables = new Drawable[2]; 179 drawables[PLAY] = getStyledDrawable(context, 180 R.styleable.lbPlaybackControlsActionIcons_play); 181 drawables[PAUSE] = getStyledDrawable(context, 182 R.styleable.lbPlaybackControlsActionIcons_pause); 183 setDrawables(drawables); 184 185 String[] labels = new String[drawables.length]; 186 labels[PLAY] = context.getString(R.string.lb_playback_controls_play); 187 labels[PAUSE] = context.getString(R.string.lb_playback_controls_pause); 188 setLabels(labels); 189 addKeyCode(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 190 addKeyCode(KeyEvent.KEYCODE_MEDIA_PLAY); 191 addKeyCode(KeyEvent.KEYCODE_MEDIA_PAUSE); 192 } 193 } 194 195 /** 196 * An action displaying an icon for fast forward. 197 */ 198 public static class FastForwardAction extends MultiAction { 199 /** 200 * Constructor 201 * @param context Context used for loading resources. 202 */ 203 public FastForwardAction(Context context) { 204 this(context, 1); 205 } 206 207 /** 208 * Constructor 209 * @param context Context used for loading resources. 210 * @param numSpeeds Number of supported fast forward speeds. 211 */ 212 public FastForwardAction(Context context, int numSpeeds) { 213 super(R.id.lb_control_fast_forward); 214 215 if (numSpeeds < 1) { 216 throw new IllegalArgumentException("numSpeeds must be > 0"); 217 } 218 Drawable[] drawables = new Drawable[numSpeeds]; 219 drawables[0] = getStyledDrawable(context, 220 R.styleable.lbPlaybackControlsActionIcons_fast_forward); 221 setDrawables(drawables); 222 223 String[] labels = new String[getActionCount()]; 224 labels[0] = context.getString(R.string.lb_playback_controls_fast_forward); 225 226 String[] labels2 = new String[getActionCount()]; 227 labels2[0] = labels[0]; 228 229 for (int i = 1; i < numSpeeds; i++) { 230 int multiplier = i + 1; 231 labels[i] = context.getResources().getString( 232 R.string.lb_control_display_fast_forward_multiplier, multiplier); 233 labels2[i] = context.getResources().getString( 234 R.string.lb_playback_controls_fast_forward_multiplier, multiplier); 235 } 236 setLabels(labels); 237 setSecondaryLabels(labels2); 238 addKeyCode(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD); 239 } 240 } 241 242 /** 243 * An action displaying an icon for rewind. 244 */ 245 public static class RewindAction extends MultiAction { 246 /** 247 * Constructor 248 * @param context Context used for loading resources. 249 */ 250 public RewindAction(Context context) { 251 this(context, 1); 252 } 253 254 /** 255 * Constructor 256 * @param context Context used for loading resources. 257 * @param numSpeeds Number of supported fast forward speeds. 258 */ 259 public RewindAction(Context context, int numSpeeds) { 260 super(R.id.lb_control_fast_rewind); 261 262 if (numSpeeds < 1) { 263 throw new IllegalArgumentException("numSpeeds must be > 0"); 264 } 265 Drawable[] drawables = new Drawable[numSpeeds]; 266 drawables[0] = getStyledDrawable(context, 267 R.styleable.lbPlaybackControlsActionIcons_rewind); 268 setDrawables(drawables); 269 270 String[] labels = new String[getActionCount()]; 271 labels[0] = context.getString(R.string.lb_playback_controls_rewind); 272 273 String[] labels2 = new String[getActionCount()]; 274 labels2[0] = labels[0]; 275 276 for (int i = 1; i < numSpeeds; i++) { 277 int multiplier = i + 1; 278 labels[i] = labels[i] = context.getResources().getString( 279 R.string.lb_control_display_rewind_multiplier, multiplier); 280 labels2[i] = context.getResources().getString( 281 R.string.lb_playback_controls_rewind_multiplier, multiplier); 282 } 283 setLabels(labels); 284 setSecondaryLabels(labels2); 285 addKeyCode(KeyEvent.KEYCODE_MEDIA_REWIND); 286 } 287 } 288 289 /** 290 * An action displaying an icon for skip next. 291 */ 292 public static class SkipNextAction extends Action { 293 /** 294 * Constructor 295 * @param context Context used for loading resources. 296 */ 297 public SkipNextAction(Context context) { 298 super(R.id.lb_control_skip_next); 299 setIcon(getStyledDrawable(context, 300 R.styleable.lbPlaybackControlsActionIcons_skip_next)); 301 setLabel1(context.getString(R.string.lb_playback_controls_skip_next)); 302 addKeyCode(KeyEvent.KEYCODE_MEDIA_NEXT); 303 } 304 } 305 306 /** 307 * An action displaying an icon for skip previous. 308 */ 309 public static class SkipPreviousAction extends Action { 310 /** 311 * Constructor 312 * @param context Context used for loading resources. 313 */ 314 public SkipPreviousAction(Context context) { 315 super(R.id.lb_control_skip_previous); 316 setIcon(getStyledDrawable(context, 317 R.styleable.lbPlaybackControlsActionIcons_skip_previous)); 318 setLabel1(context.getString(R.string.lb_playback_controls_skip_previous)); 319 addKeyCode(KeyEvent.KEYCODE_MEDIA_PREVIOUS); 320 } 321 } 322 323 /** 324 * An action displaying an icon for picture-in-picture. 325 */ 326 public static class PictureInPictureAction extends Action { 327 /** 328 * Constructor 329 * @param context Context used for loading resources. 330 */ 331 public PictureInPictureAction(Context context) { 332 super(R.id.lb_control_picture_in_picture); 333 setIcon(getStyledDrawable(context, 334 R.styleable.lbPlaybackControlsActionIcons_picture_in_picture)); 335 setLabel1(context.getString(R.string.lb_playback_controls_picture_in_picture)); 336 addKeyCode(KeyEvent.KEYCODE_WINDOW); 337 } 338 } 339 340 /** 341 * An action displaying an icon for "more actions". 342 */ 343 public static class MoreActions extends Action { 344 /** 345 * Constructor 346 * @param context Context used for loading resources. 347 */ 348 public MoreActions(Context context) { 349 super(R.id.lb_control_more_actions); 350 setIcon(context.getResources().getDrawable(R.drawable.lb_ic_more)); 351 setLabel1(context.getString(R.string.lb_playback_controls_more_actions)); 352 } 353 } 354 355 /** 356 * A base class for displaying a thumbs action. 357 */ 358 public static abstract class ThumbsAction extends MultiAction { 359 /** 360 * Action index for the solid thumb icon. 361 */ 362 public static int SOLID = 0; 363 364 /** 365 * Action index for the outline thumb icon. 366 */ 367 public static int OUTLINE = 1; 368 369 /** 370 * Constructor 371 * @param context Context used for loading resources. 372 */ 373 public ThumbsAction(int id, Context context, int solidIconIndex, int outlineIconIndex) { 374 super(id); 375 Drawable[] drawables = new Drawable[2]; 376 drawables[SOLID] = getStyledDrawable(context, solidIconIndex); 377 drawables[OUTLINE] = getStyledDrawable(context, outlineIconIndex); 378 setDrawables(drawables); 379 } 380 } 381 382 /** 383 * An action displaying an icon for thumbs up. 384 */ 385 public static class ThumbsUpAction extends ThumbsAction { 386 public ThumbsUpAction(Context context) { 387 super(R.id.lb_control_thumbs_up, context, 388 R.styleable.lbPlaybackControlsActionIcons_thumb_up, 389 R.styleable.lbPlaybackControlsActionIcons_thumb_up_outline); 390 String[] labels = new String[getActionCount()]; 391 labels[SOLID] = context.getString(R.string.lb_playback_controls_thumb_up); 392 labels[OUTLINE] = context.getString(R.string.lb_playback_controls_thumb_up_outline); 393 setLabels(labels); 394 } 395 } 396 397 /** 398 * An action displaying an icon for thumbs down. 399 */ 400 public static class ThumbsDownAction extends ThumbsAction { 401 public ThumbsDownAction(Context context) { 402 super(R.id.lb_control_thumbs_down, context, 403 R.styleable.lbPlaybackControlsActionIcons_thumb_down, 404 R.styleable.lbPlaybackControlsActionIcons_thumb_down_outline); 405 String[] labels = new String[getActionCount()]; 406 labels[SOLID] = context.getString(R.string.lb_playback_controls_thumb_down); 407 labels[OUTLINE] = context.getString(R.string.lb_playback_controls_thumb_down_outline); 408 setLabels(labels); 409 } 410 } 411 412 /** 413 * An action for displaying three repeat states: none, one, or all. 414 */ 415 public static class RepeatAction extends MultiAction { 416 /** 417 * Action index for the repeat-none icon. 418 */ 419 public static int NONE = 0; 420 421 /** 422 * Action index for the repeat-all icon. 423 */ 424 public static int ALL = 1; 425 426 /** 427 * Action index for the repeat-one icon. 428 */ 429 public static int ONE = 2; 430 431 /** 432 * Constructor 433 * @param context Context used for loading resources. 434 */ 435 public RepeatAction(Context context) { 436 this(context, getIconHighlightColor(context)); 437 } 438 439 /** 440 * Constructor 441 * @param context Context used for loading resources 442 * @param highlightColor Color to display the repeat-all and repeat0one icons. 443 */ 444 public RepeatAction(Context context, int highlightColor) { 445 this(context, highlightColor, highlightColor); 446 } 447 448 /** 449 * Constructor 450 * @param context Context used for loading resources 451 * @param repeatAllColor Color to display the repeat-all icon. 452 * @param repeatOneColor Color to display the repeat-one icon. 453 */ 454 public RepeatAction(Context context, int repeatAllColor, int repeatOneColor) { 455 super(R.id.lb_control_repeat); 456 Drawable[] drawables = new Drawable[3]; 457 BitmapDrawable repeatDrawable = (BitmapDrawable) getStyledDrawable(context, 458 R.styleable.lbPlaybackControlsActionIcons_repeat); 459 BitmapDrawable repeatOneDrawable = (BitmapDrawable) getStyledDrawable(context, 460 R.styleable.lbPlaybackControlsActionIcons_repeat_one); 461 drawables[NONE] = repeatDrawable; 462 drawables[ALL] = repeatDrawable == null ? null 463 : new BitmapDrawable(context.getResources(), 464 createBitmap(repeatDrawable.getBitmap(), repeatAllColor)); 465 drawables[ONE] = repeatOneDrawable == null ? null 466 : new BitmapDrawable(context.getResources(), 467 createBitmap(repeatOneDrawable.getBitmap(), repeatOneColor)); 468 setDrawables(drawables); 469 470 String[] labels = new String[drawables.length]; 471 // Note, labels denote the action taken when clicked 472 labels[NONE] = context.getString(R.string.lb_playback_controls_repeat_all); 473 labels[ALL] = context.getString(R.string.lb_playback_controls_repeat_one); 474 labels[ONE] = context.getString(R.string.lb_playback_controls_repeat_none); 475 setLabels(labels); 476 } 477 } 478 479 /** 480 * An action for displaying a shuffle icon. 481 */ 482 public static class ShuffleAction extends MultiAction { 483 public static int OFF = 0; 484 public static int ON = 1; 485 486 /** 487 * Constructor 488 * @param context Context used for loading resources. 489 */ 490 public ShuffleAction(Context context) { 491 this(context, getIconHighlightColor(context)); 492 } 493 494 /** 495 * Constructor 496 * @param context Context used for loading resources. 497 * @param highlightColor Color for the highlighted icon state. 498 */ 499 public ShuffleAction(Context context, int highlightColor) { 500 super(R.id.lb_control_shuffle); 501 BitmapDrawable uncoloredDrawable = (BitmapDrawable) getStyledDrawable(context, 502 R.styleable.lbPlaybackControlsActionIcons_shuffle); 503 Drawable[] drawables = new Drawable[2]; 504 drawables[OFF] = uncoloredDrawable; 505 drawables[ON] = new BitmapDrawable(context.getResources(), 506 createBitmap(uncoloredDrawable.getBitmap(), highlightColor)); 507 setDrawables(drawables); 508 509 String[] labels = new String[drawables.length]; 510 labels[OFF] = context.getString(R.string.lb_playback_controls_shuffle_enable); 511 labels[ON] = context.getString(R.string.lb_playback_controls_shuffle_disable); 512 setLabels(labels); 513 } 514 } 515 516 /** 517 * An action for displaying a HQ (High Quality) icon. 518 */ 519 public static class HighQualityAction extends MultiAction { 520 public static int OFF = 0; 521 public static int ON = 1; 522 523 /** 524 * Constructor 525 * @param context Context used for loading resources. 526 */ 527 public HighQualityAction(Context context) { 528 this(context, getIconHighlightColor(context)); 529 } 530 531 /** 532 * Constructor 533 * @param context Context used for loading resources. 534 * @param highlightColor Color for the highlighted icon state. 535 */ 536 public HighQualityAction(Context context, int highlightColor) { 537 super(R.id.lb_control_high_quality); 538 BitmapDrawable uncoloredDrawable = (BitmapDrawable) getStyledDrawable(context, 539 R.styleable.lbPlaybackControlsActionIcons_high_quality); 540 Drawable[] drawables = new Drawable[2]; 541 drawables[OFF] = uncoloredDrawable; 542 drawables[ON] = new BitmapDrawable(context.getResources(), 543 createBitmap(uncoloredDrawable.getBitmap(), highlightColor)); 544 setDrawables(drawables); 545 546 String[] labels = new String[drawables.length]; 547 labels[OFF] = context.getString(R.string.lb_playback_controls_high_quality_enable); 548 labels[ON] = context.getString(R.string.lb_playback_controls_high_quality_disable); 549 setLabels(labels); 550 } 551 } 552 553 /** 554 * An action for displaying a CC (Closed Captioning) icon. 555 */ 556 public static class ClosedCaptioningAction extends MultiAction { 557 public static int OFF = 0; 558 public static int ON = 1; 559 560 /** 561 * Constructor 562 * @param context Context used for loading resources. 563 */ 564 public ClosedCaptioningAction(Context context) { 565 this(context, getIconHighlightColor(context)); 566 } 567 568 /** 569 * Constructor 570 * @param context Context used for loading resources. 571 * @param highlightColor Color for the highlighted icon state. 572 */ 573 public ClosedCaptioningAction(Context context, int highlightColor) { 574 super(R.id.lb_control_closed_captioning); 575 BitmapDrawable uncoloredDrawable = (BitmapDrawable) getStyledDrawable(context, 576 R.styleable.lbPlaybackControlsActionIcons_closed_captioning); 577 Drawable[] drawables = new Drawable[2]; 578 drawables[OFF] = uncoloredDrawable; 579 drawables[ON] = new BitmapDrawable(context.getResources(), 580 createBitmap(uncoloredDrawable.getBitmap(), highlightColor)); 581 setDrawables(drawables); 582 583 String[] labels = new String[drawables.length]; 584 labels[OFF] = context.getString(R.string.lb_playback_controls_closed_captioning_enable); 585 labels[ON] = context.getString(R.string.lb_playback_controls_closed_captioning_disable); 586 setLabels(labels); 587 } 588 } 589 590 private static Bitmap createBitmap(Bitmap bitmap, int color) { 591 Bitmap dst = bitmap.copy(bitmap.getConfig(), true); 592 Canvas canvas = new Canvas(dst); 593 Paint paint = new Paint(); 594 paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)); 595 canvas.drawBitmap(bitmap, 0, 0, paint); 596 return dst; 597 } 598 599 private static int getIconHighlightColor(Context context) { 600 TypedValue outValue = new TypedValue(); 601 if (context.getTheme().resolveAttribute(R.attr.playbackControlsIconHighlightColor, 602 outValue, true)) { 603 return outValue.data; 604 } 605 return context.getResources().getColor(R.color.lb_playback_icon_highlight_no_theme); 606 } 607 608 private static Drawable getStyledDrawable(Context context, int index) { 609 TypedValue outValue = new TypedValue(); 610 if (!context.getTheme().resolveAttribute( 611 R.attr.playbackControlsActionIcons, outValue, false)) { 612 return null; 613 } 614 TypedArray array = context.getTheme().obtainStyledAttributes(outValue.data, 615 R.styleable.lbPlaybackControlsActionIcons); 616 Drawable drawable = array.getDrawable(index); 617 array.recycle(); 618 return drawable; 619 } 620 621 private Object mItem; 622 private Drawable mImageDrawable; 623 private ObjectAdapter mPrimaryActionsAdapter; 624 private ObjectAdapter mSecondaryActionsAdapter; 625 private int mTotalTimeMs; 626 private int mCurrentTimeMs; 627 private int mBufferedProgressMs; 628 private OnPlaybackStateChangedListener mListener; 629 630 /** 631 * Constructor for a PlaybackControlsRow that displays some details from 632 * the given item. 633 * 634 * @param item The main item for the row. 635 */ 636 public PlaybackControlsRow(Object item) { 637 mItem = item; 638 } 639 640 /** 641 * Constructor for a PlaybackControlsRow that has no item details. 642 */ 643 public PlaybackControlsRow() { 644 } 645 646 /** 647 * Returns the main item for the details page. 648 */ 649 public final Object getItem() { 650 return mItem; 651 } 652 653 /** 654 * Sets a {link @Drawable} image for this row. 655 * <p>If set after the row has been bound to a view, the adapter must be notified that 656 * this row has changed.</p> 657 * 658 * @param drawable The drawable to set. 659 */ 660 public final void setImageDrawable(Drawable drawable) { 661 mImageDrawable = drawable; 662 } 663 664 /** 665 * Sets a {@link Bitmap} for this row. 666 * <p>If set after the row has been bound to a view, the adapter must be notified that 667 * this row has changed.</p> 668 * 669 * @param context The context to retrieve display metrics from. 670 * @param bm The bitmap to set. 671 */ 672 public final void setImageBitmap(Context context, Bitmap bm) { 673 mImageDrawable = new BitmapDrawable(context.getResources(), bm); 674 } 675 676 /** 677 * Returns the image {@link Drawable} of this row. 678 * 679 * @return The overview's image drawable, or null if no drawable has been 680 * assigned. 681 */ 682 public final Drawable getImageDrawable() { 683 return mImageDrawable; 684 } 685 686 /** 687 * Sets the primary actions {@link ObjectAdapter}. 688 * <p>If set after the row has been bound to a view, the adapter must be notified that 689 * this row has changed.</p> 690 */ 691 public final void setPrimaryActionsAdapter(ObjectAdapter adapter) { 692 mPrimaryActionsAdapter = adapter; 693 } 694 695 /** 696 * Sets the secondary actions {@link ObjectAdapter}. 697 * <p>If set after the row has been bound to a view, the adapter must be notified that 698 * this row has changed.</p> 699 */ 700 public final void setSecondaryActionsAdapter(ObjectAdapter adapter) { 701 mSecondaryActionsAdapter = adapter; 702 } 703 704 /** 705 * Returns the primary actions {@link ObjectAdapter}. 706 */ 707 public final ObjectAdapter getPrimaryActionsAdapter() { 708 return mPrimaryActionsAdapter; 709 } 710 711 /** 712 * Returns the secondary actions {@link ObjectAdapter}. 713 */ 714 public final ObjectAdapter getSecondaryActionsAdapter() { 715 return mSecondaryActionsAdapter; 716 } 717 718 /** 719 * Sets the total time in milliseconds for the playback controls row. 720 * <p>If set after the row has been bound to a view, the adapter must be notified that 721 * this row has changed.</p> 722 */ 723 public void setTotalTime(int ms) { 724 mTotalTimeMs = ms; 725 } 726 727 /** 728 * Returns the total time in milliseconds for the playback controls row. 729 */ 730 public int getTotalTime() { 731 return mTotalTimeMs; 732 } 733 734 /** 735 * Sets the current time in milliseconds for the playback controls row. 736 * If this row is bound to a view, the view will automatically 737 * be updated to reflect the new value. 738 */ 739 public void setCurrentTime(int ms) { 740 if (mCurrentTimeMs != ms) { 741 mCurrentTimeMs = ms; 742 currentTimeChanged(); 743 } 744 } 745 746 /** 747 * Returns the current time in milliseconds for the playback controls row. 748 */ 749 public int getCurrentTime() { 750 return mCurrentTimeMs; 751 } 752 753 /** 754 * Sets the buffered progress for the playback controls row. 755 * If this row is bound to a view, the view will automatically 756 * be updated to reflect the new value. 757 */ 758 public void setBufferedProgress(int ms) { 759 if (mBufferedProgressMs != ms) { 760 mBufferedProgressMs = ms; 761 bufferedProgressChanged(); 762 } 763 } 764 765 /** 766 * Returns the buffered progress for the playback controls row. 767 */ 768 public int getBufferedProgress() { 769 return mBufferedProgressMs; 770 } 771 772 /** 773 * Returns the Action associated with the given keycode, or null if no associated action exists. 774 * Searches the primary adapter first, then the secondary adapter. 775 */ 776 public Action getActionForKeyCode(int keyCode) { 777 Action action = getActionForKeyCode(getPrimaryActionsAdapter(), keyCode); 778 if (action != null) { 779 return action; 780 } 781 return getActionForKeyCode(getSecondaryActionsAdapter(), keyCode); 782 } 783 784 /** 785 * Returns the Action associated with the given keycode, or null if no associated action exists. 786 */ 787 public Action getActionForKeyCode(ObjectAdapter adapter, int keyCode) { 788 if (adapter != mPrimaryActionsAdapter && adapter != mSecondaryActionsAdapter) { 789 throw new IllegalArgumentException("Invalid adapter"); 790 } 791 for (int i = 0; i < adapter.size(); i++) { 792 Action action = (Action) adapter.get(i); 793 if (action.respondsToKeyCode(keyCode)) { 794 return action; 795 } 796 } 797 return null; 798 } 799 800 interface OnPlaybackStateChangedListener { 801 public void onCurrentTimeChanged(int currentTimeMs); 802 public void onBufferedProgressChanged(int bufferedProgressMs); 803 } 804 805 /** 806 * Sets a listener to be called when the playback state changes. 807 */ 808 void setOnPlaybackStateChangedListener(OnPlaybackStateChangedListener listener) { 809 mListener = listener; 810 } 811 812 /** 813 * Returns the playback state listener. 814 */ 815 OnPlaybackStateChangedListener getOnPlaybackStateChangedListener() { 816 return mListener; 817 } 818 819 private void currentTimeChanged() { 820 if (mListener != null) { 821 mListener.onCurrentTimeChanged(mCurrentTimeMs); 822 } 823 } 824 825 private void bufferedProgressChanged() { 826 if (mListener != null) { 827 mListener.onBufferedProgressChanged(mBufferedProgressMs); 828 } 829 } 830 } 831