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