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