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