1/* This file is auto-generated from PlaybackOverlayFragment.java. DO NOT MODIFY. */ 2 3/* 4 * Copyright (C) 2014 The Android Open Source Project 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 * in compliance with the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software distributed under the License 12 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 * or implied. See the License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16package android.support.v17.leanback.app; 17 18import android.graphics.Color; 19import android.graphics.drawable.ColorDrawable; 20import android.animation.Animator; 21import android.animation.AnimatorInflater; 22import android.animation.TimeInterpolator; 23import android.animation.ValueAnimator; 24import android.support.v17.leanback.widget.Action; 25import android.support.v17.leanback.widget.PlaybackControlsRow; 26import android.view.InputEvent; 27import android.view.animation.AccelerateInterpolator; 28import android.animation.ValueAnimator.AnimatorUpdateListener; 29import android.content.Context; 30import android.os.Bundle; 31import android.os.Handler; 32import android.os.Message; 33import android.support.v7.widget.RecyclerView; 34import android.support.v17.leanback.R; 35import android.support.v17.leanback.animation.LogAccelerateInterpolator; 36import android.support.v17.leanback.animation.LogDecelerateInterpolator; 37import android.support.v17.leanback.widget.ItemBridgeAdapter; 38import android.support.v17.leanback.widget.ObjectAdapter; 39import android.support.v17.leanback.widget.ObjectAdapter.DataObserver; 40import android.support.v17.leanback.widget.PlaybackControlsRowPresenter; 41import android.support.v17.leanback.widget.Presenter; 42import android.support.v17.leanback.widget.PresenterSelector; 43import android.support.v17.leanback.widget.RowPresenter; 44import android.support.v17.leanback.widget.VerticalGridView; 45import android.util.Log; 46import android.view.KeyEvent; 47import android.view.LayoutInflater; 48import android.view.MotionEvent; 49import android.view.View; 50import android.view.ViewGroup; 51 52import java.util.ArrayList; 53 54/** 55 * A fragment for displaying playback controls and related content. 56 * <p> 57 * A PlaybackOverlaySupportFragment renders the elements of its {@link ObjectAdapter} as a set 58 * of rows in a vertical list. The Adapter's {@link PresenterSelector} must maintain subclasses 59 * of {@link RowPresenter}. 60 * </p> 61 * <p> 62 * An instance of {@link android.support.v17.leanback.widget.PlaybackControlsRow} is expected to be 63 * at position 0 in the adapter. 64 * </p> 65 */ 66public class PlaybackOverlaySupportFragment extends DetailsSupportFragment { 67 68 /** 69 * No background. 70 */ 71 public static final int BG_NONE = 0; 72 73 /** 74 * A dark translucent background. 75 */ 76 public static final int BG_DARK = 1; 77 78 /** 79 * A light translucent background. 80 */ 81 public static final int BG_LIGHT = 2; 82 83 /** 84 * Listener allowing the application to receive notification of fade in and/or fade out 85 * completion events. 86 */ 87 public static class OnFadeCompleteListener { 88 public void onFadeInComplete() { 89 } 90 public void onFadeOutComplete() { 91 } 92 } 93 94 /** 95 * Interface allowing the application to handle input events. 96 */ 97 public interface InputEventHandler { 98 /** 99 * Called when an {@link InputEvent} is received. 100 * 101 * @return If the event should be consumed, return true. To allow the event to 102 * continue on to the next handler, return false. 103 */ 104 public boolean handleInputEvent(InputEvent event); 105 } 106 107 private static final String TAG = "PlaybackOverlaySupportFragment"; 108 private static final boolean DEBUG = false; 109 private static final int ANIMATION_MULTIPLIER = 1; 110 111 private static int START_FADE_OUT = 1; 112 113 // Fading status 114 private static final int IDLE = 0; 115 private static final int IN = 1; 116 private static final int OUT = 2; 117 118 private int mPaddingTop; 119 private int mPaddingBottom; 120 private View mRootView; 121 private int mBackgroundType = BG_DARK; 122 private int mBgDarkColor; 123 private int mBgLightColor; 124 private int mShowTimeMs; 125 private int mMajorFadeTranslateY, mMinorFadeTranslateY; 126 private int mAnimationTranslateY; 127 private OnFadeCompleteListener mFadeCompleteListener; 128 private InputEventHandler mInputEventHandler; 129 private boolean mFadingEnabled = true; 130 private int mFadingStatus = IDLE; 131 private int mBgAlpha; 132 private ValueAnimator mBgFadeInAnimator, mBgFadeOutAnimator; 133 private ValueAnimator mControlRowFadeInAnimator, mControlRowFadeOutAnimator; 134 private ValueAnimator mDescriptionFadeInAnimator, mDescriptionFadeOutAnimator; 135 private ValueAnimator mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator; 136 private boolean mTranslateAnimationEnabled; 137 private boolean mResetControlsToPrimaryActionsPending; 138 private RecyclerView.ItemAnimator mItemAnimator; 139 140 private final Animator.AnimatorListener mFadeListener = 141 new Animator.AnimatorListener() { 142 @Override 143 public void onAnimationStart(Animator animation) { 144 enableVerticalGridAnimations(false); 145 } 146 @Override 147 public void onAnimationRepeat(Animator animation) { 148 } 149 @Override 150 public void onAnimationCancel(Animator animation) { 151 } 152 @Override 153 public void onAnimationEnd(Animator animation) { 154 if (DEBUG) Log.v(TAG, "onAnimationEnd " + mBgAlpha); 155 if (mBgAlpha > 0) { 156 enableVerticalGridAnimations(true); 157 startFadeTimer(); 158 if (mFadeCompleteListener != null) { 159 mFadeCompleteListener.onFadeInComplete(); 160 } 161 } else { 162 VerticalGridView verticalView = getVerticalGridView(); 163 // reset focus to the primary actions only if the selected row was the controls row 164 if (verticalView != null && verticalView.getSelectedPosition() == 0) { 165 resetControlsToPrimaryActions(null); 166 } 167 if (mFadeCompleteListener != null) { 168 mFadeCompleteListener.onFadeOutComplete(); 169 } 170 } 171 mFadingStatus = IDLE; 172 } 173 }; 174 175 private final Handler mHandler = new Handler() { 176 @Override 177 public void handleMessage(Message message) { 178 if (message.what == START_FADE_OUT && mFadingEnabled) { 179 fade(false); 180 } 181 } 182 }; 183 184 private final VerticalGridView.OnTouchInterceptListener mOnTouchInterceptListener = 185 new VerticalGridView.OnTouchInterceptListener() { 186 public boolean onInterceptTouchEvent(MotionEvent event) { 187 return onInterceptInputEvent(event); 188 } 189 }; 190 191 private final VerticalGridView.OnKeyInterceptListener mOnKeyInterceptListener = 192 new VerticalGridView.OnKeyInterceptListener() { 193 public boolean onInterceptKeyEvent(KeyEvent event) { 194 return onInterceptInputEvent(event); 195 } 196 }; 197 198 private void setBgAlpha(int alpha) { 199 mBgAlpha = alpha; 200 if (mRootView != null) { 201 mRootView.getBackground().setAlpha(alpha); 202 } 203 } 204 205 private void enableVerticalGridAnimations(boolean enable) { 206 if (getVerticalGridView() != null) { 207 getVerticalGridView().setAnimateChildLayout(enable); 208 } 209 } 210 211 private void resetControlsToPrimaryActions(ItemBridgeAdapter.ViewHolder vh) { 212 if (vh == null && getVerticalGridView() != null) { 213 vh = (ItemBridgeAdapter.ViewHolder) getVerticalGridView().findViewHolderForPosition(0); 214 } 215 if (vh == null) { 216 mResetControlsToPrimaryActionsPending = true; 217 } else if (vh.getPresenter() instanceof PlaybackControlsRowPresenter) { 218 mResetControlsToPrimaryActionsPending = false; 219 ((PlaybackControlsRowPresenter) vh.getPresenter()).showPrimaryActions( 220 (PlaybackControlsRowPresenter.ViewHolder) vh.getViewHolder()); 221 } 222 } 223 224 /** 225 * Enables or disables view fading. If enabled, 226 * the view will be faded in when the fragment starts, 227 * and will fade out after a time period. The timeout 228 * period is reset each time {@link #tickle} is called. 229 * 230 */ 231 public void setFadingEnabled(boolean enabled) { 232 if (DEBUG) Log.v(TAG, "setFadingEnabled " + enabled); 233 if (enabled != mFadingEnabled) { 234 mFadingEnabled = enabled; 235 if (mFadingEnabled) { 236 if (isResumed() && mFadingStatus == IDLE 237 && !mHandler.hasMessages(START_FADE_OUT)) { 238 startFadeTimer(); 239 } 240 } else { 241 // Ensure fully opaque 242 mHandler.removeMessages(START_FADE_OUT); 243 fade(true); 244 } 245 } 246 } 247 248 /** 249 * Returns true if view fading is enabled. 250 */ 251 public boolean isFadingEnabled() { 252 return mFadingEnabled; 253 } 254 255 /** 256 * Sets the listener to be called when fade in or out has completed. 257 */ 258 public void setFadeCompleteListener(OnFadeCompleteListener listener) { 259 mFadeCompleteListener = listener; 260 } 261 262 /** 263 * Returns the listener to be called when fade in or out has completed. 264 */ 265 public OnFadeCompleteListener getFadeCompleteListener() { 266 return mFadeCompleteListener; 267 } 268 269 /** 270 * Sets the input event handler. 271 */ 272 public final void setInputEventHandler(InputEventHandler handler) { 273 mInputEventHandler = handler; 274 } 275 276 /** 277 * Returns the input event handler. 278 */ 279 public final InputEventHandler getInputEventHandler() { 280 return mInputEventHandler; 281 } 282 283 /** 284 * Tickles the playback controls. Fades in the view if it was faded out, 285 * otherwise resets the fade out timer. Tickling on input events is handled 286 * by the fragment. 287 */ 288 public void tickle() { 289 if (DEBUG) Log.v(TAG, "tickle enabled " + mFadingEnabled + " isResumed " + isResumed()); 290 if (!mFadingEnabled || !isResumed()) { 291 return; 292 } 293 if (mHandler.hasMessages(START_FADE_OUT)) { 294 // Restart the timer 295 startFadeTimer(); 296 } else { 297 fade(true); 298 } 299 } 300 301 /** 302 * Fades out the playback overlay immediately. 303 */ 304 public void fadeOut() { 305 mHandler.removeMessages(START_FADE_OUT); 306 fade(false); 307 } 308 309 private boolean areControlsHidden() { 310 return mFadingStatus == IDLE && mBgAlpha == 0; 311 } 312 313 private boolean onInterceptInputEvent(InputEvent event) { 314 final boolean controlsHidden = areControlsHidden(); 315 if (DEBUG) Log.v(TAG, "onInterceptInputEvent hidden " + controlsHidden + " " + event); 316 boolean consumeEvent = false; 317 int keyCode = KeyEvent.KEYCODE_UNKNOWN; 318 319 if (mInputEventHandler != null) { 320 consumeEvent = mInputEventHandler.handleInputEvent(event); 321 } 322 if (event instanceof KeyEvent) { 323 keyCode = ((KeyEvent) event).getKeyCode(); 324 } 325 326 switch (keyCode) { 327 case KeyEvent.KEYCODE_DPAD_CENTER: 328 case KeyEvent.KEYCODE_DPAD_DOWN: 329 case KeyEvent.KEYCODE_DPAD_UP: 330 case KeyEvent.KEYCODE_DPAD_LEFT: 331 case KeyEvent.KEYCODE_DPAD_RIGHT: 332 // Event may be consumed; regardless, if controls are hidden then these keys will 333 // bring up the controls. 334 if (controlsHidden) { 335 consumeEvent = true; 336 } 337 tickle(); 338 break; 339 case KeyEvent.KEYCODE_BACK: 340 case KeyEvent.KEYCODE_ESCAPE: 341 // If fading enabled and controls are not hidden, back will be consumed to fade 342 // them out (even if the key was consumed by the handler). 343 if (mFadingEnabled && !controlsHidden) { 344 consumeEvent = true; 345 mHandler.removeMessages(START_FADE_OUT); 346 fade(false); 347 } else if (consumeEvent) { 348 tickle(); 349 } 350 break; 351 default: 352 if (consumeEvent) { 353 tickle(); 354 } 355 } 356 return consumeEvent; 357 } 358 359 @Override 360 public void onResume() { 361 super.onResume(); 362 if (mFadingEnabled) { 363 setBgAlpha(0); 364 fade(true); 365 } 366 getVerticalGridView().setOnTouchInterceptListener(mOnTouchInterceptListener); 367 getVerticalGridView().setOnKeyInterceptListener(mOnKeyInterceptListener); 368 } 369 370 private void startFadeTimer() { 371 if (mHandler != null) { 372 mHandler.removeMessages(START_FADE_OUT); 373 mHandler.sendEmptyMessageDelayed(START_FADE_OUT, mShowTimeMs); 374 } 375 } 376 377 private static ValueAnimator loadAnimator(Context context, int resId) { 378 ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(context, resId); 379 animator.setDuration(animator.getDuration() * ANIMATION_MULTIPLIER); 380 return animator; 381 } 382 383 private void loadBgAnimator() { 384 AnimatorUpdateListener listener = new AnimatorUpdateListener() { 385 @Override 386 public void onAnimationUpdate(ValueAnimator arg0) { 387 setBgAlpha((Integer) arg0.getAnimatedValue()); 388 } 389 }; 390 391 mBgFadeInAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_in); 392 mBgFadeInAnimator.addUpdateListener(listener); 393 mBgFadeInAnimator.addListener(mFadeListener); 394 395 mBgFadeOutAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_out); 396 mBgFadeOutAnimator.addUpdateListener(listener); 397 mBgFadeOutAnimator.addListener(mFadeListener); 398 } 399 400 private TimeInterpolator mLogDecelerateInterpolator = new LogDecelerateInterpolator(100,0); 401 private TimeInterpolator mLogAccelerateInterpolator = new LogAccelerateInterpolator(100,0); 402 403 private View getControlRowView() { 404 if (getVerticalGridView() == null) { 405 return null; 406 } 407 RecyclerView.ViewHolder vh = getVerticalGridView().findViewHolderForPosition(0); 408 if (vh == null) { 409 return null; 410 } 411 return vh.itemView; 412 } 413 414 private void loadControlRowAnimator() { 415 final AnimatorListener listener = new AnimatorListener() { 416 @Override 417 void getViews(ArrayList<View> views) { 418 View view = getControlRowView(); 419 if (view != null) { 420 views.add(view); 421 } 422 } 423 }; 424 final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() { 425 @Override 426 public void onAnimationUpdate(ValueAnimator arg0) { 427 View view = getControlRowView(); 428 if (view != null) { 429 final float fraction = (Float) arg0.getAnimatedValue(); 430 if (DEBUG) Log.v(TAG, "fraction " + fraction); 431 view.setAlpha(fraction); 432 view.setTranslationY((float) mAnimationTranslateY * (1f - fraction)); 433 } 434 } 435 }; 436 437 mControlRowFadeInAnimator = loadAnimator( 438 getActivity(), R.animator.lb_playback_controls_fade_in); 439 mControlRowFadeInAnimator.addUpdateListener(updateListener); 440 mControlRowFadeInAnimator.addListener(listener); 441 mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator); 442 443 mControlRowFadeOutAnimator = loadAnimator( 444 getActivity(), R.animator.lb_playback_controls_fade_out); 445 mControlRowFadeOutAnimator.addUpdateListener(updateListener); 446 mControlRowFadeOutAnimator.addListener(listener); 447 mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator); 448 } 449 450 private void loadOtherRowAnimator() { 451 final AnimatorListener listener = new AnimatorListener() { 452 @Override 453 void getViews(ArrayList<View> views) { 454 if (getVerticalGridView() == null) { 455 return; 456 } 457 final int count = getVerticalGridView().getChildCount(); 458 for (int i = 0; i < count; i++) { 459 View view = getVerticalGridView().getChildAt(i); 460 if (view != null) { 461 views.add(view); 462 } 463 } 464 } 465 }; 466 final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() { 467 @Override 468 public void onAnimationUpdate(ValueAnimator arg0) { 469 if (getVerticalGridView() == null) { 470 return; 471 } 472 final float fraction = (Float) arg0.getAnimatedValue(); 473 for (View view : listener.mViews) { 474 if (getVerticalGridView().getChildPosition(view) > 0) { 475 view.setAlpha(fraction); 476 view.setTranslationY((float) mAnimationTranslateY * (1f - fraction)); 477 } 478 } 479 } 480 }; 481 482 mOtherRowFadeInAnimator = loadAnimator( 483 getActivity(), R.animator.lb_playback_controls_fade_in); 484 mOtherRowFadeInAnimator.addListener(listener); 485 mOtherRowFadeInAnimator.addUpdateListener(updateListener); 486 mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator); 487 488 mOtherRowFadeOutAnimator = loadAnimator( 489 getActivity(), R.animator.lb_playback_controls_fade_out); 490 mOtherRowFadeOutAnimator.addListener(listener); 491 mOtherRowFadeOutAnimator.addUpdateListener(updateListener); 492 mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator()); 493 } 494 495 private void loadDescriptionAnimator() { 496 AnimatorUpdateListener listener = new AnimatorUpdateListener() { 497 @Override 498 public void onAnimationUpdate(ValueAnimator arg0) { 499 if (getVerticalGridView() == null) { 500 return; 501 } 502 ItemBridgeAdapter.ViewHolder adapterVh = (ItemBridgeAdapter.ViewHolder) 503 getVerticalGridView().findViewHolderForPosition(0); 504 if (adapterVh != null && adapterVh.getViewHolder() 505 instanceof PlaybackControlsRowPresenter.ViewHolder) { 506 final Presenter.ViewHolder vh = ((PlaybackControlsRowPresenter.ViewHolder) 507 adapterVh.getViewHolder()).mDescriptionViewHolder; 508 if (vh != null) { 509 vh.view.setAlpha((Float) arg0.getAnimatedValue()); 510 } 511 } 512 } 513 }; 514 515 mDescriptionFadeInAnimator = loadAnimator( 516 getActivity(), R.animator.lb_playback_description_fade_in); 517 mDescriptionFadeInAnimator.addUpdateListener(listener); 518 mDescriptionFadeInAnimator.setInterpolator(mLogDecelerateInterpolator); 519 520 mDescriptionFadeOutAnimator = loadAnimator( 521 getActivity(), R.animator.lb_playback_description_fade_out); 522 mDescriptionFadeOutAnimator.addUpdateListener(listener); 523 } 524 525 private void fade(boolean fadeIn) { 526 if (DEBUG) Log.v(TAG, "fade " + fadeIn); 527 if (getView() == null) { 528 return; 529 } 530 if ((fadeIn && mFadingStatus == IN) || (!fadeIn && mFadingStatus == OUT)) { 531 if (DEBUG) Log.v(TAG, "requested fade in progress"); 532 return; 533 } 534 if ((fadeIn && mBgAlpha == 255) || (!fadeIn && mBgAlpha == 0)) { 535 if (DEBUG) Log.v(TAG, "fade is no-op"); 536 return; 537 } 538 539 mAnimationTranslateY = getVerticalGridView().getSelectedPosition() == 0 ? 540 mMajorFadeTranslateY : mMinorFadeTranslateY; 541 542 if (mFadingStatus == IDLE) { 543 if (fadeIn) { 544 mBgFadeInAnimator.start(); 545 mControlRowFadeInAnimator.start(); 546 mOtherRowFadeInAnimator.start(); 547 mDescriptionFadeInAnimator.start(); 548 } else { 549 mBgFadeOutAnimator.start(); 550 mControlRowFadeOutAnimator.start(); 551 mOtherRowFadeOutAnimator.start(); 552 mDescriptionFadeOutAnimator.start(); 553 } 554 } else { 555 if (fadeIn) { 556 mBgFadeOutAnimator.reverse(); 557 mControlRowFadeOutAnimator.reverse(); 558 mOtherRowFadeOutAnimator.reverse(); 559 mDescriptionFadeOutAnimator.reverse(); 560 } else { 561 mBgFadeInAnimator.reverse(); 562 mControlRowFadeInAnimator.reverse(); 563 mOtherRowFadeInAnimator.reverse(); 564 mDescriptionFadeInAnimator.reverse(); 565 } 566 } 567 568 // If fading in while control row is focused, set initial translationY so 569 // views slide in from below. 570 if (fadeIn && mFadingStatus == IDLE) { 571 final int count = getVerticalGridView().getChildCount(); 572 for (int i = 0; i < count; i++) { 573 getVerticalGridView().getChildAt(i).setTranslationY(mAnimationTranslateY); 574 } 575 } 576 577 mFadingStatus = fadeIn ? IN : OUT; 578 } 579 580 /** 581 * Sets the list of rows for the fragment. 582 */ 583 @Override 584 public void setAdapter(ObjectAdapter adapter) { 585 if (getAdapter() != null) { 586 getAdapter().unregisterObserver(mObserver); 587 } 588 super.setAdapter(adapter); 589 if (adapter != null) { 590 adapter.registerObserver(mObserver); 591 } 592 } 593 594 @Override 595 void setVerticalGridViewLayout(VerticalGridView listview) { 596 if (listview == null) { 597 return; 598 } 599 // Padding affects alignment when last row is focused 600 // (last is first when there's only one row). 601 setPadding(listview, mPaddingTop, mPaddingBottom); 602 603 // Item alignment affects focused row that isn't the last. 604 listview.setItemAlignmentOffset(0); 605 listview.setItemAlignmentOffsetPercent(50); 606 607 // Push rows to the bottom. 608 listview.setWindowAlignmentOffset(0); 609 listview.setWindowAlignmentOffsetPercent(50); 610 listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE); 611 } 612 613 private static void setPadding(View view, int paddingTop, int paddingBottom) { 614 view.setPadding(view.getPaddingLeft(), paddingTop, 615 view.getPaddingRight(), paddingBottom); 616 } 617 618 @Override 619 public void onCreate(Bundle savedInstanceState) { 620 super.onCreate(savedInstanceState); 621 622 mPaddingTop = 623 getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_top); 624 mPaddingBottom = 625 getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom); 626 mBgDarkColor = 627 getResources().getColor(R.color.lb_playback_controls_background_dark); 628 mBgLightColor = 629 getResources().getColor(R.color.lb_playback_controls_background_light); 630 mShowTimeMs = 631 getResources().getInteger(R.integer.lb_playback_controls_show_time_ms); 632 mMajorFadeTranslateY = 633 getResources().getDimensionPixelSize(R.dimen.lb_playback_major_fade_translate_y); 634 mMinorFadeTranslateY = 635 getResources().getDimensionPixelSize(R.dimen.lb_playback_minor_fade_translate_y); 636 637 loadBgAnimator(); 638 loadControlRowAnimator(); 639 loadOtherRowAnimator(); 640 loadDescriptionAnimator(); 641 } 642 643 /** 644 * Sets the background type. 645 * 646 * @param type One of BG_LIGHT, BG_DARK, or BG_NONE. 647 */ 648 public void setBackgroundType(int type) { 649 switch (type) { 650 case BG_LIGHT: 651 case BG_DARK: 652 case BG_NONE: 653 if (type != mBackgroundType) { 654 mBackgroundType = type; 655 updateBackground(); 656 } 657 break; 658 default: 659 throw new IllegalArgumentException("Invalid background type"); 660 } 661 } 662 663 /** 664 * Returns the background type. 665 */ 666 public int getBackgroundType() { 667 return mBackgroundType; 668 } 669 670 private void updateBackground() { 671 if (mRootView != null) { 672 int color = mBgDarkColor; 673 switch (mBackgroundType) { 674 case BG_DARK: break; 675 case BG_LIGHT: color = mBgLightColor; break; 676 case BG_NONE: color = Color.TRANSPARENT; break; 677 } 678 mRootView.setBackground(new ColorDrawable(color)); 679 } 680 } 681 682 private void updateControlsBottomSpace(ItemBridgeAdapter.ViewHolder vh) { 683 // Add extra space between rows 0 and 1 684 if (vh == null && getVerticalGridView() != null) { 685 vh = (ItemBridgeAdapter.ViewHolder) 686 getVerticalGridView().findViewHolderForPosition(0); 687 } 688 if (vh != null && vh.getPresenter() instanceof PlaybackControlsRowPresenter) { 689 final int adapterSize = getAdapter() == null ? 0 : getAdapter().size(); 690 ((PlaybackControlsRowPresenter) vh.getPresenter()).showBottomSpace( 691 (PlaybackControlsRowPresenter.ViewHolder) vh.getViewHolder(), 692 adapterSize > 1); 693 } 694 } 695 696 private final ItemBridgeAdapter.AdapterListener mAdapterListener = 697 new ItemBridgeAdapter.AdapterListener() { 698 @Override 699 public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder vh) { 700 if (DEBUG) Log.v(TAG, "onAttachedToWindow " + vh.getViewHolder().view); 701 if ((mFadingStatus == IDLE && mBgAlpha == 0) || mFadingStatus == OUT) { 702 if (DEBUG) Log.v(TAG, "setting alpha to 0"); 703 vh.getViewHolder().view.setAlpha(0); 704 } 705 if (vh.getPosition() == 0 && mResetControlsToPrimaryActionsPending) { 706 resetControlsToPrimaryActions(vh); 707 } 708 } 709 @Override 710 public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder vh) { 711 if (DEBUG) Log.v(TAG, "onDetachedFromWindow " + vh.getViewHolder().view); 712 // Reset animation state 713 vh.getViewHolder().view.setAlpha(1f); 714 vh.getViewHolder().view.setTranslationY(0); 715 if (vh.getViewHolder() instanceof PlaybackControlsRowPresenter.ViewHolder) { 716 Presenter.ViewHolder descriptionVh = ((PlaybackControlsRowPresenter.ViewHolder) 717 vh.getViewHolder()).mDescriptionViewHolder; 718 if (descriptionVh != null) { 719 descriptionVh.view.setAlpha(1f); 720 } 721 } 722 } 723 @Override 724 public void onBind(ItemBridgeAdapter.ViewHolder vh) { 725 if (vh.getPosition() == 0) { 726 updateControlsBottomSpace(vh); 727 } 728 } 729 }; 730 731 @Override 732 public View onCreateView(LayoutInflater inflater, ViewGroup container, 733 Bundle savedInstanceState) { 734 mRootView = super.onCreateView(inflater, container, savedInstanceState); 735 mBgAlpha = 255; 736 updateBackground(); 737 getRowsSupportFragment().setExternalAdapterListener(mAdapterListener); 738 return mRootView; 739 } 740 741 @Override 742 public void onDestroyView() { 743 mRootView = null; 744 super.onDestroyView(); 745 } 746 747 private final DataObserver mObserver = new DataObserver() { 748 public void onChanged() { 749 updateControlsBottomSpace(null); 750 } 751 }; 752 753 static abstract class AnimatorListener implements Animator.AnimatorListener { 754 ArrayList<View> mViews = new ArrayList<View>(); 755 ArrayList<Integer> mLayerType = new ArrayList<Integer>(); 756 757 public void onAnimationCancel(Animator animation) { 758 } 759 public void onAnimationRepeat(Animator animation) { 760 } 761 public void onAnimationStart(Animator animation) { 762 getViews(mViews); 763 for (View view : mViews) { 764 mLayerType.add(view.getLayerType()); 765 view.setLayerType(View.LAYER_TYPE_HARDWARE, null); 766 } 767 } 768 public void onAnimationEnd(Animator animation) { 769 for (int i = 0; i < mViews.size(); i++) { 770 mViews.get(i).setLayerType(mLayerType.get(i), null); 771 } 772 mLayerType.clear(); 773 mViews.clear(); 774 } 775 abstract void getViews(ArrayList<View> views); 776 777 }; 778} 779