PlaybackControlsRow.java revision cf992de2d34abb8228dc6cb39fffe97346823a37
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.support.v17.leanback.R; 17import android.util.TypedValue; 18import android.content.Context; 19import android.content.res.TypedArray; 20import android.graphics.Bitmap; 21import android.graphics.BitmapFactory; 22import android.graphics.Canvas; 23import android.graphics.Color; 24import android.graphics.Paint; 25import android.graphics.PorterDuff; 26import android.graphics.PorterDuffColorFilter; 27import android.graphics.drawable.BitmapDrawable; 28import android.graphics.drawable.Drawable; 29 30/** 31 * A 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 * Controls are specified via an {@link ObjectAdapter} containing one or more 37 * {@link Action}s. 38 * 39 * Adapters should have their {@link PresenterSelector} set to an instance of 40 * {@link ControlButtonPresenterSelector}. 41 * 42 */ 43public class PlaybackControlsRow extends Row { 44 45 /** 46 * Base class for an action comprised of a series of icons. 47 */ 48 public static abstract class MultiAction extends Action { 49 private int mIndex; 50 private Drawable[] mDrawables; 51 52 /** 53 * Constructor 54 * @param id The id of the Action. 55 */ 56 public MultiAction(int id) { 57 super(id); 58 } 59 60 /** 61 * Sets the array of drawables. The size of the array defines the range 62 * of valid indices for this action. 63 */ 64 public void setDrawables(Drawable[] drawables) { 65 mDrawables = drawables; 66 setIndex(0); 67 } 68 69 /** 70 * Returns the number of drawables. 71 */ 72 public int getNumberOfDrawables() { 73 return mDrawables.length; 74 } 75 76 /** 77 * Returns the drawable at the given index. 78 */ 79 public Drawable getDrawable(int index) { 80 return mDrawables[index]; 81 } 82 83 /** 84 * Increments the index, wrapping to zero once the end is reached. 85 */ 86 public void nextIndex() { 87 setIndex(mIndex < mDrawables.length - 1 ? mIndex + 1 : 0); 88 } 89 90 /** 91 * Sets the current index. 92 */ 93 public void setIndex(int index) { 94 mIndex = index; 95 setIcon(mDrawables[mIndex]); 96 } 97 98 /** 99 * Gets the current index. 100 */ 101 public int getIndex() { 102 return mIndex; 103 } 104 } 105 106 /** 107 * An action displaying icons for play and pause. 108 */ 109 public static class PlayPauseAction extends MultiAction { 110 /** 111 * Action index for the play icon. 112 */ 113 public static int PLAY = 0; 114 115 /** 116 * Action index for the pause icon. 117 */ 118 public static int PAUSE = 1; 119 120 /** 121 * Constructor 122 * @param context Context used for loading resources. 123 */ 124 public PlayPauseAction(Context context) { 125 super(R.id.lb_control_play_pause); 126 Drawable[] drawables = new Drawable[2]; 127 drawables[PLAY] = getStyledDrawable(context, 128 R.styleable.lbPlaybackControlsActionIcons_play); 129 drawables[PAUSE] = getStyledDrawable(context, 130 R.styleable.lbPlaybackControlsActionIcons_pause); 131 setDrawables(drawables); 132 } 133 134 @Override 135 public String toString() { 136 return "PlayPauseAction"; 137 } 138 } 139 140 /** 141 * An action displaying an icon for fast forward. 142 */ 143 public static class FastForwardAction extends Action { 144 /** 145 * Constructor 146 * @param context Context used for loading resources. 147 */ 148 public FastForwardAction(Context context) { 149 super(R.id.lb_control_fast_forward); 150 setIcon(getStyledDrawable(context, 151 R.styleable.lbPlaybackControlsActionIcons_fast_forward)); 152 } 153 154 @Override 155 public String toString() { 156 return "FastForwardAction"; 157 } 158 } 159 160 /** 161 * An action displaying an icon for rewind. 162 */ 163 public static class RewindAction extends Action { 164 /** 165 * Constructor 166 * @param context Context used for loading resources. 167 */ 168 public RewindAction(Context context) { 169 super(R.id.lb_control_fast_rewind); 170 setIcon(getStyledDrawable(context, 171 R.styleable.lbPlaybackControlsActionIcons_rewind)); 172 } 173 174 @Override 175 public String toString() { 176 return "RewindAction"; 177 } 178 } 179 180 /** 181 * An action displaying an icon for skip next. 182 */ 183 public static class SkipNextAction extends Action { 184 /** 185 * Constructor 186 * @param context Context used for loading resources. 187 */ 188 public SkipNextAction(Context context) { 189 super(R.id.lb_control_skip_next); 190 setIcon(getStyledDrawable(context, 191 R.styleable.lbPlaybackControlsActionIcons_skip_next)); 192 } 193 194 @Override 195 public String toString() { 196 return "SkipNextAction"; 197 } 198 } 199 200 /** 201 * An action displaying an icon for skip previous. 202 */ 203 public static class SkipPreviousAction extends Action { 204 /** 205 * Constructor 206 * @param context Context used for loading resources. 207 */ 208 public SkipPreviousAction(Context context) { 209 super(R.id.lb_control_skip_previous); 210 setIcon(getStyledDrawable(context, 211 R.styleable.lbPlaybackControlsActionIcons_skip_previous)); 212 } 213 214 @Override 215 public String toString() { 216 return "SkipPreviousAction"; 217 } 218 } 219 220 /** 221 * An action displaying an icon for "more actions". 222 */ 223 public static class MoreActions extends Action { 224 /** 225 * Constructor 226 * @param context Context used for loading resources. 227 */ 228 public MoreActions(Context context) { 229 super(R.id.lb_control_more_actions); 230 setIcon(context.getResources().getDrawable(R.drawable.lb_ic_more)); 231 } 232 233 @Override 234 public String toString() { 235 return "MoreActions"; 236 } 237 } 238 239 /** 240 * A base class for displaying a thumbs action. 241 */ 242 public static abstract class ThumbsAction extends MultiAction { 243 /** 244 * Action index for the solid thumb icon. 245 */ 246 public static int SOLID = 0; 247 248 /** 249 * Action index for the outline thumb icon. 250 */ 251 public static int OUTLINE = 1; 252 253 /** 254 * Constructor 255 * @param context Context used for loading resources. 256 */ 257 public ThumbsAction(int id, Context context, int solidIconIndex, int outlineIconIndex) { 258 super(id); 259 Drawable[] drawables = new Drawable[2]; 260 drawables[SOLID] = getStyledDrawable(context, solidIconIndex); 261 drawables[OUTLINE] = getStyledDrawable(context, outlineIconIndex); 262 setDrawables(drawables); 263 } 264 } 265 266 /** 267 * An action displaying an icon for thumbs up. 268 */ 269 public static class ThumbsUpAction extends ThumbsAction { 270 public ThumbsUpAction(Context context) { 271 super(R.id.lb_control_thumbs_up, context, 272 R.styleable.lbPlaybackControlsActionIcons_thumb_up, 273 R.styleable.lbPlaybackControlsActionIcons_thumb_up_outline); 274 } 275 276 @Override 277 public String toString() { 278 return "ThumbsUpAction"; 279 } 280 } 281 282 /** 283 * An action displaying an icon for thumbs down. 284 */ 285 public static class ThumbsDownAction extends ThumbsAction { 286 public ThumbsDownAction(Context context) { 287 super(R.id.lb_control_thumbs_down, context, 288 R.styleable.lbPlaybackControlsActionIcons_thumb_down, 289 R.styleable.lbPlaybackControlsActionIcons_thumb_down_outline); 290 } 291 292 @Override 293 public String toString() { 294 return "ThumbsDownAction"; 295 } 296 } 297 298 /** 299 * An action for displaying three repeat states: none, one, or all. 300 */ 301 public static class RepeatAction extends MultiAction { 302 /** 303 * Action index for the repeat-none icon. 304 */ 305 public static int NONE = 0; 306 307 /** 308 * Action index for the repeat-all icon. 309 */ 310 public static int ALL = 1; 311 312 /** 313 * Action index for the repeat-one icon. 314 */ 315 public static int ONE = 2; 316 317 /** 318 * Constructor 319 * @param context Context used for loading resources. 320 */ 321 public RepeatAction(Context context) { 322 this(context, getColorFromTheme(context, 323 R.attr.playbackControlsIconHighlightColor)); 324 } 325 326 /** 327 * Constructor 328 * @param context Context used for loading resources 329 * @param highlightColor Color to display the repeat-all and repeat0one icons. 330 */ 331 public RepeatAction(Context context, int highlightColor) { 332 this(context, highlightColor, highlightColor); 333 } 334 335 /** 336 * Constructor 337 * @param context Context used for loading resources 338 * @param repeatAllColor Color to display the repeat-all icon. 339 * @param repeatOneColor Color to display the repeat-one icon. 340 */ 341 public RepeatAction(Context context, int repeatAllColor, int repeatOneColor) { 342 super(R.id.lb_control_repeat); 343 Drawable[] drawables = new Drawable[3]; 344 BitmapDrawable repeatDrawable = (BitmapDrawable) getStyledDrawable(context, 345 R.styleable.lbPlaybackControlsActionIcons_repeat); 346 BitmapDrawable repeatOneDrawable = (BitmapDrawable) getStyledDrawable(context, 347 R.styleable.lbPlaybackControlsActionIcons_repeat_one); 348 drawables[NONE] = repeatDrawable; 349 drawables[ALL] = new BitmapDrawable(context.getResources(), 350 createBitmap(repeatDrawable.getBitmap(), repeatAllColor)); 351 drawables[ONE] = new BitmapDrawable(context.getResources(), 352 createBitmap(repeatOneDrawable.getBitmap(), repeatOneColor)); 353 setDrawables(drawables); 354 } 355 356 @Override 357 public String toString() { 358 return "RepeatAction"; 359 } 360 } 361 362 /** 363 * An action for displaying a shuffle icon. 364 */ 365 public static class ShuffleAction extends MultiAction { 366 public static int OFF = 0; 367 public static int ON = 1; 368 369 /** 370 * Constructor 371 * @param context Context used for loading resources. 372 */ 373 public ShuffleAction(Context context) { 374 this(context, getColorFromTheme(context, 375 R.attr.playbackControlsIconHighlightColor)); 376 } 377 378 /** 379 * Constructor 380 * @param context Context used for loading resources. 381 * @param highlightColor Color for the highlighted icon state. 382 */ 383 public ShuffleAction(Context context, int highlightColor) { 384 super(R.id.lb_control_shuffle); 385 BitmapDrawable uncoloredDrawable = (BitmapDrawable) getStyledDrawable(context, 386 R.styleable.lbPlaybackControlsActionIcons_shuffle); 387 Drawable[] drawables = new Drawable[2]; 388 drawables[OFF] = uncoloredDrawable; 389 drawables[ON] = new BitmapDrawable(context.getResources(), 390 createBitmap(uncoloredDrawable.getBitmap(), highlightColor)); 391 setDrawables(drawables); 392 } 393 394 @Override 395 public String toString() { 396 return "ShuffleAction"; 397 } 398 } 399 400 /** 401 * An action for displaying a HQ (High Quality) icon. 402 */ 403 public static class HighQualityAction extends MultiAction { 404 public static int OFF = 0; 405 public static int ON = 1; 406 407 /** 408 * Constructor 409 * @param context Context used for loading resources. 410 */ 411 public HighQualityAction(Context context) { 412 this(context, getColorFromTheme(context, 413 R.attr.playbackControlsIconHighlightColor)); 414 } 415 416 /** 417 * Constructor 418 * @param context Context used for loading resources. 419 * @param highlightColor Color for the highlighted icon state. 420 */ 421 public HighQualityAction(Context context, int highlightColor) { 422 super(R.id.lb_control_high_quality); 423 BitmapDrawable uncoloredDrawable = (BitmapDrawable) getStyledDrawable(context, 424 R.styleable.lbPlaybackControlsActionIcons_high_quality); 425 Drawable[] drawables = new Drawable[2]; 426 drawables[OFF] = uncoloredDrawable; 427 drawables[ON] = new BitmapDrawable(context.getResources(), 428 createBitmap(uncoloredDrawable.getBitmap(), highlightColor)); 429 setDrawables(drawables); 430 } 431 432 @Override 433 public String toString() { 434 return "HighQualityAction"; 435 } 436 } 437 438 /** 439 * An action for displaying a CC (Closed Captioning) icon. 440 */ 441 public static class ClosedCaptioningAction extends MultiAction { 442 public static int OFF = 0; 443 public static int ON = 1; 444 445 /** 446 * Constructor 447 * @param context Context used for loading resources. 448 */ 449 public ClosedCaptioningAction(Context context) { 450 this(context, getColorFromTheme(context, 451 R.attr.playbackControlsIconHighlightColor)); 452 } 453 454 /** 455 * Constructor 456 * @param context Context used for loading resources. 457 * @param highlightColor Color for the highlighted icon state. 458 */ 459 public ClosedCaptioningAction(Context context, int highlightColor) { 460 super(R.id.lb_control_high_quality); 461 BitmapDrawable uncoloredDrawable = (BitmapDrawable) getStyledDrawable(context, 462 R.styleable.lbPlaybackControlsActionIcons_closed_captioning); 463 Drawable[] drawables = new Drawable[2]; 464 drawables[OFF] = uncoloredDrawable; 465 drawables[ON] = new BitmapDrawable(context.getResources(), 466 createBitmap(uncoloredDrawable.getBitmap(), highlightColor)); 467 setDrawables(drawables); 468 } 469 470 @Override 471 public String toString() { 472 return "ClosedCaptioningAction"; 473 } 474 } 475 476 private static Bitmap createBitmap(Bitmap bitmap, int color) { 477 Bitmap dst = bitmap.copy(bitmap.getConfig(), true); 478 Canvas canvas = new Canvas(dst); 479 Paint paint = new Paint(); 480 paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)); 481 canvas.drawBitmap(bitmap, 0, 0, paint); 482 return dst; 483 } 484 485 private static int getColorFromTheme(Context context, int attributeResId) { 486 TypedValue outValue = new TypedValue(); 487 context.getTheme().resolveAttribute(attributeResId, outValue, true); 488 return outValue.data; 489 } 490 491 private static Drawable getStyledDrawable(Context context, int index) { 492 TypedValue outValue = new TypedValue(); 493 context.getTheme().resolveAttribute( 494 R.attr.playbackControlsActionIcons, outValue, false); 495 TypedArray array = context.getTheme().obtainStyledAttributes(outValue.data, 496 R.styleable.lbPlaybackControlsActionIcons); 497 Drawable drawable = array.getDrawable(index); 498 array.recycle(); 499 return drawable; 500 } 501 502 private Object mItem; 503 private Drawable mImageDrawable; 504 private ObjectAdapter mPrimaryActionsAdapter; 505 private ObjectAdapter mSecondaryActionsAdapter; 506 private int mTotalTimeMs; 507 private int mCurrentTimeMs; 508 private int mBufferedProgressMs; 509 private OnPlaybackStateChangedListener mListener; 510 511 /** 512 * Constructor for a PlaybackControlsRow that displays some details from 513 * the given item. 514 * 515 * @param item The main item for the row. 516 */ 517 public PlaybackControlsRow(Object item) { 518 mItem = item; 519 } 520 521 /** 522 * Constructor for a PlaybackControlsRow that has no item details. 523 */ 524 public PlaybackControlsRow() { 525 } 526 527 /** 528 * Gets the main item for the details page. 529 */ 530 public final Object getItem() { 531 return mItem; 532 } 533 534 /** 535 * Sets a {link @Drawable} image for this row. 536 * 537 * @param drawable The drawable to set. 538 */ 539 public final void setImageDrawable(Drawable drawable) { 540 mImageDrawable = drawable; 541 } 542 543 /** 544 * Sets a {@link Bitmap} for this row. 545 * 546 * @param context The context to retrieve display metrics from. 547 * @param bm The bitmap to set. 548 */ 549 public final void setImageBitmap(Context context, Bitmap bm) { 550 mImageDrawable = new BitmapDrawable(context.getResources(), bm); 551 } 552 553 /** 554 * Gets the image {@link Drawable} of this row. 555 * 556 * @return The overview's image drawable, or null if no drawable has been 557 * assigned. 558 */ 559 public final Drawable getImageDrawable() { 560 return mImageDrawable; 561 } 562 563 /** 564 * Sets the primary actions {@link ObjectAdapter}. 565 */ 566 public final void setPrimaryActionsAdapter(ObjectAdapter adapter) { 567 mPrimaryActionsAdapter = adapter; 568 } 569 570 /** 571 * Sets the secondary actions {@link ObjectAdapter}. 572 */ 573 public final void setSecondaryActionsAdapter(ObjectAdapter adapter) { 574 mSecondaryActionsAdapter = adapter; 575 } 576 577 /** 578 * Returns the primary actions {@link ObjectAdapter}. 579 */ 580 public final ObjectAdapter getPrimaryActionsAdapter() { 581 return mPrimaryActionsAdapter; 582 } 583 584 /** 585 * Returns the secondary actions {@link ObjectAdapter}. 586 */ 587 public final ObjectAdapter getSecondaryActionsAdapter() { 588 return mSecondaryActionsAdapter; 589 } 590 591 /** 592 * Sets the total time in milliseconds for the playback controls row. 593 */ 594 public void setTotalTime(int ms) { 595 mTotalTimeMs = ms; 596 } 597 598 /** 599 * Returns the total time in milliseconds for the playback controls row. 600 */ 601 public int getTotalTime() { 602 return mTotalTimeMs; 603 } 604 605 /** 606 * Sets the current time in milliseconds for the playback controls row. 607 */ 608 public void setCurrentTime(int ms) { 609 if (mCurrentTimeMs != ms) { 610 mCurrentTimeMs = ms; 611 currentTimeChanged(); 612 } 613 } 614 615 /** 616 * Returns the current time in milliseconds for the playback controls row. 617 */ 618 public int getCurrentTime() { 619 return mCurrentTimeMs; 620 } 621 622 /** 623 * Sets the buffered progress for the playback controls row. 624 */ 625 public void setBufferedProgress(int ms) { 626 if (mBufferedProgressMs != ms) { 627 mBufferedProgressMs = ms; 628 bufferedProgressChanged(); 629 } 630 } 631 632 /** 633 * Returns the buffered progress for the playback controls row. 634 */ 635 public int getBufferedProgress() { 636 return mBufferedProgressMs; 637 } 638 639 interface OnPlaybackStateChangedListener { 640 public void onCurrentTimeChanged(int currentTimeMs); 641 public void onBufferedProgressChanged(int bufferedProgressMs); 642 } 643 644 /** 645 * Sets a listener to be called when the playback state changes. 646 */ 647 public void setOnPlaybackStateChangedListener(OnPlaybackStateChangedListener listener) { 648 mListener = listener; 649 } 650 651 /** 652 * Returns the playback state listener. 653 */ 654 public OnPlaybackStateChangedListener getOnPlaybackStateChangedListener() { 655 return mListener; 656 } 657 658 private void currentTimeChanged() { 659 if (mListener != null) { 660 mListener.onCurrentTimeChanged(mCurrentTimeMs); 661 } 662 } 663 664 private void bufferedProgressChanged() { 665 if (mListener != null) { 666 mListener.onBufferedProgressChanged(mBufferedProgressMs); 667 } 668 } 669} 670