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