PlaybackOverlayFragment.java revision f47fb1e34efd538c322f7539893272ba847cdbdc
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 (mFadingEnabled) { 223 if (isResumed() && mFadingStatus == IDLE 224 && !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 * Returns true if view fading is enabled. 237 */ 238 public boolean isFadingEnabled() { 239 return mFadingEnabled; 240 } 241 242 /** 243 * Sets the listener to be called when fade in or out has completed. 244 */ 245 public void setFadeCompleteListener(OnFadeCompleteListener listener) { 246 mFadeCompleteListener = listener; 247 } 248 249 /** 250 * Returns the listener to be called when fade in or out has completed. 251 */ 252 public OnFadeCompleteListener getFadeCompleteListener() { 253 return mFadeCompleteListener; 254 } 255 256 /** 257 * Sets the input event handler. 258 */ 259 public final void setInputEventHandler(InputEventHandler handler) { 260 mInputEventHandler = handler; 261 } 262 263 /** 264 * Returns the input event handler. 265 */ 266 public final InputEventHandler getInputEventHandler() { 267 return mInputEventHandler; 268 } 269 270 /** 271 * Tickles the playback controls. Fades in the view if it was faded out, 272 * otherwise resets the fade out timer. Tickling on input events is handled 273 * by the fragment. 274 */ 275 public void tickle() { 276 if (DEBUG) Log.v(TAG, "tickle enabled " + mFadingEnabled + " isResumed " + isResumed()); 277 if (!mFadingEnabled || !isResumed()) { 278 return; 279 } 280 if (mHandler.hasMessages(START_FADE_OUT)) { 281 // Restart the timer 282 startFadeTimer(); 283 } else { 284 fade(true); 285 } 286 } 287 288 private static boolean isConsumableKey(KeyEvent keyEvent) { 289 if (keyEvent.isSystem()) { 290 return false; 291 } 292 return true; 293 } 294 295 private boolean onInterceptInputEvent(InputEvent event) { 296 if (DEBUG) Log.v(TAG, "onInterceptInputEvent status " + mFadingStatus + " event " + event); 297 boolean consumeEvent = (mFadingStatus == IDLE && mBgAlpha == 0); 298 if (event instanceof KeyEvent) { 299 if (consumeEvent) { 300 consumeEvent = isConsumableKey((KeyEvent) event); 301 } 302 int keyCode = ((KeyEvent) event).getKeyCode(); 303 // Back key typically means we're leaving the fragment 304 if (keyCode != KeyEvent.KEYCODE_BACK) { 305 tickle(); 306 } 307 } else { 308 tickle(); 309 } 310 if (!consumeEvent && mInputEventHandler != null) { 311 consumeEvent = mInputEventHandler.handleInputEvent(event); 312 } 313 return consumeEvent; 314 } 315 316 @Override 317 public void onResume() { 318 super.onResume(); 319 if (mFadingEnabled) { 320 setBgAlpha(0); 321 fade(true); 322 } 323 getVerticalGridView().setOnTouchInterceptListener(mOnTouchInterceptListener); 324 getVerticalGridView().setOnMotionInterceptListener(mOnMotionInterceptListener); 325 getVerticalGridView().setOnKeyInterceptListener(mOnKeyInterceptListener); 326 } 327 328 private void startFadeTimer() { 329 if (mHandler != null) { 330 mHandler.removeMessages(START_FADE_OUT); 331 mHandler.sendEmptyMessageDelayed(START_FADE_OUT, mShowTimeMs); 332 } 333 } 334 335 private static ValueAnimator loadAnimator(Context context, int resId) { 336 ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(context, resId); 337 animator.setDuration(animator.getDuration() * ANIMATION_MULTIPLIER); 338 return animator; 339 } 340 341 private void loadBgAnimator() { 342 AnimatorUpdateListener listener = new AnimatorUpdateListener() { 343 @Override 344 public void onAnimationUpdate(ValueAnimator arg0) { 345 setBgAlpha((Integer) arg0.getAnimatedValue()); 346 } 347 }; 348 349 mBgFadeInAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_in); 350 mBgFadeInAnimator.addUpdateListener(listener); 351 mBgFadeInAnimator.addListener(mFadeListener); 352 353 mBgFadeOutAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_out); 354 mBgFadeOutAnimator.addUpdateListener(listener); 355 mBgFadeOutAnimator.addListener(mFadeListener); 356 } 357 358 private TimeInterpolator mLogDecelerateInterpolator = new LogDecelerateInterpolator(100,0); 359 private TimeInterpolator mLogAccelerateInterpolator = new LogAccelerateInterpolator(100,0); 360 361 private View getControlRowView() { 362 if (getVerticalGridView() == null) { 363 return null; 364 } 365 RecyclerView.ViewHolder vh = getVerticalGridView().findViewHolderForPosition(0); 366 if (vh == null) { 367 return null; 368 } 369 return vh.itemView; 370 } 371 372 private void loadControlRowAnimator() { 373 final AnimatorListener listener = new AnimatorListener() { 374 @Override 375 void getViews(ArrayList<View> views) { 376 View view = getControlRowView(); 377 if (view != null) { 378 views.add(view); 379 } 380 } 381 }; 382 final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() { 383 @Override 384 public void onAnimationUpdate(ValueAnimator arg0) { 385 View view = getControlRowView(); 386 if (view != null) { 387 final float fraction = (Float) arg0.getAnimatedValue(); 388 if (DEBUG) Log.v(TAG, "fraction " + fraction); 389 view.setAlpha(fraction); 390 view.setTranslationY((float) mAnimationTranslateY * (1f - fraction)); 391 } 392 } 393 }; 394 395 mControlRowFadeInAnimator = loadAnimator( 396 getActivity(), R.animator.lb_playback_controls_fade_in); 397 mControlRowFadeInAnimator.addUpdateListener(updateListener); 398 mControlRowFadeInAnimator.addListener(listener); 399 mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator); 400 401 mControlRowFadeOutAnimator = loadAnimator( 402 getActivity(), R.animator.lb_playback_controls_fade_out); 403 mControlRowFadeOutAnimator.addUpdateListener(updateListener); 404 mControlRowFadeOutAnimator.addListener(listener); 405 mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator); 406 } 407 408 private void loadOtherRowAnimator() { 409 final AnimatorListener listener = new AnimatorListener() { 410 @Override 411 void getViews(ArrayList<View> views) { 412 if (getVerticalGridView() == null) { 413 return; 414 } 415 final int count = getVerticalGridView().getChildCount(); 416 for (int i = 0; i < count; i++) { 417 View view = getVerticalGridView().getChildAt(i); 418 if (view != null) { 419 views.add(view); 420 } 421 } 422 } 423 }; 424 final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() { 425 @Override 426 public void onAnimationUpdate(ValueAnimator arg0) { 427 final float fraction = (Float) arg0.getAnimatedValue(); 428 for (View view : listener.mViews) { 429 if (getVerticalGridView().getChildPosition(view) > 0) { 430 view.setAlpha(fraction); 431 view.setTranslationY((float) mAnimationTranslateY * (1f - fraction)); 432 } 433 } 434 } 435 }; 436 437 mOtherRowFadeInAnimator = loadAnimator( 438 getActivity(), R.animator.lb_playback_controls_fade_in); 439 mOtherRowFadeInAnimator.addListener(listener); 440 mOtherRowFadeInAnimator.addUpdateListener(updateListener); 441 mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator); 442 443 mOtherRowFadeOutAnimator = loadAnimator( 444 getActivity(), R.animator.lb_playback_controls_fade_out); 445 mOtherRowFadeOutAnimator.addListener(listener); 446 mOtherRowFadeOutAnimator.addUpdateListener(updateListener); 447 mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator()); 448 } 449 450 private void loadDescriptionAnimator() { 451 AnimatorUpdateListener listener = new AnimatorUpdateListener() { 452 @Override 453 public void onAnimationUpdate(ValueAnimator arg0) { 454 if (getVerticalGridView() == null) { 455 return; 456 } 457 ItemBridgeAdapter.ViewHolder adapterVh = (ItemBridgeAdapter.ViewHolder) 458 getVerticalGridView().findViewHolderForPosition(0); 459 if (adapterVh != null && adapterVh.getViewHolder() 460 instanceof PlaybackControlsRowPresenter.ViewHolder) { 461 final Presenter.ViewHolder vh = ((PlaybackControlsRowPresenter.ViewHolder) 462 adapterVh.getViewHolder()).mDescriptionViewHolder; 463 if (vh != null) { 464 vh.view.setAlpha((Float) arg0.getAnimatedValue()); 465 } 466 } 467 } 468 }; 469 470 mDescriptionFadeInAnimator = loadAnimator( 471 getActivity(), R.animator.lb_playback_description_fade_in); 472 mDescriptionFadeInAnimator.addUpdateListener(listener); 473 mDescriptionFadeInAnimator.setInterpolator(mLogDecelerateInterpolator); 474 475 mDescriptionFadeOutAnimator = loadAnimator( 476 getActivity(), R.animator.lb_playback_description_fade_out); 477 mDescriptionFadeOutAnimator.addUpdateListener(listener); 478 } 479 480 private void fade(boolean fadeIn) { 481 if (DEBUG) Log.v(TAG, "fade " + fadeIn); 482 if (getView() == null) { 483 return; 484 } 485 if ((fadeIn && mFadingStatus == IN) || (!fadeIn && mFadingStatus == OUT)) { 486 if (DEBUG) Log.v(TAG, "requested fade in progress"); 487 return; 488 } 489 if ((fadeIn && mBgAlpha == 255) || (!fadeIn && mBgAlpha == 0)) { 490 if (DEBUG) Log.v(TAG, "fade is no-op"); 491 return; 492 } 493 494 mAnimationTranslateY = getVerticalGridView().getSelectedPosition() == 0 ? 495 mMajorFadeTranslateY : mMinorFadeTranslateY; 496 497 if (mFadingStatus == IDLE) { 498 if (fadeIn) { 499 mBgFadeInAnimator.start(); 500 mControlRowFadeInAnimator.start(); 501 mOtherRowFadeInAnimator.start(); 502 mDescriptionFadeInAnimator.start(); 503 } else { 504 mBgFadeOutAnimator.start(); 505 mControlRowFadeOutAnimator.start(); 506 mOtherRowFadeOutAnimator.start(); 507 mDescriptionFadeOutAnimator.start(); 508 } 509 } else { 510 if (fadeIn) { 511 mBgFadeOutAnimator.reverse(); 512 mControlRowFadeOutAnimator.reverse(); 513 mOtherRowFadeOutAnimator.reverse(); 514 mDescriptionFadeOutAnimator.reverse(); 515 } else { 516 mBgFadeInAnimator.reverse(); 517 mControlRowFadeInAnimator.reverse(); 518 mOtherRowFadeInAnimator.reverse(); 519 mDescriptionFadeInAnimator.reverse(); 520 } 521 } 522 523 // If fading in while control row is focused, set initial translationY so 524 // views slide in from below. 525 if (fadeIn && mFadingStatus == IDLE) { 526 final int count = getVerticalGridView().getChildCount(); 527 for (int i = 0; i < count; i++) { 528 getVerticalGridView().getChildAt(i).setTranslationY(mAnimationTranslateY); 529 } 530 } 531 532 mFadingStatus = fadeIn ? IN : OUT; 533 } 534 535 /** 536 * Sets the list of rows for the fragment. 537 */ 538 @Override 539 public void setAdapter(ObjectAdapter adapter) { 540 if (getAdapter() != null) { 541 getAdapter().unregisterObserver(mObserver); 542 } 543 super.setAdapter(adapter); 544 if (adapter != null) { 545 adapter.registerObserver(mObserver); 546 } 547 } 548 549 @Override 550 void setVerticalGridViewLayout(VerticalGridView listview) { 551 if (listview == null) { 552 return; 553 } 554 // Padding affects alignment when last row is focused 555 // (last is first when there's only one row). 556 setBottomPadding(listview, mPaddingBottom); 557 558 // Item alignment affects focused row that isn't the last. 559 listview.setItemAlignmentOffset(mAlignPosition); 560 listview.setItemAlignmentOffsetPercent(100); 561 562 // Push rows to the bottom. 563 listview.setWindowAlignmentOffset(0); 564 listview.setWindowAlignmentOffsetPercent(100); 565 listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE); 566 } 567 568 private static void setBottomPadding(View view, int padding) { 569 view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), 570 view.getPaddingRight(), padding); 571 } 572 573 @Override 574 public void onCreate(Bundle savedInstanceState) { 575 super.onCreate(savedInstanceState); 576 577 mAlignPosition = 578 getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_align_bottom); 579 mPaddingBottom = 580 getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom); 581 mBgDarkColor = 582 getResources().getColor(R.color.lb_playback_controls_background_dark); 583 mBgLightColor = 584 getResources().getColor(R.color.lb_playback_controls_background_light); 585 mShowTimeMs = 586 getResources().getInteger(R.integer.lb_playback_controls_show_time_ms); 587 mMajorFadeTranslateY = 588 getResources().getDimensionPixelSize(R.dimen.lb_playback_major_fade_translate_y); 589 mMinorFadeTranslateY = 590 getResources().getDimensionPixelSize(R.dimen.lb_playback_minor_fade_translate_y); 591 592 loadBgAnimator(); 593 loadControlRowAnimator(); 594 loadOtherRowAnimator(); 595 loadDescriptionAnimator(); 596 } 597 598 /** 599 * Sets the background type. 600 * 601 * @param type One of BG_LIGHT, BG_DARK, or BG_NONE. 602 */ 603 public void setBackgroundType(int type) { 604 switch (type) { 605 case BG_LIGHT: 606 case BG_DARK: 607 case BG_NONE: 608 if (type != mBackgroundType) { 609 mBackgroundType = type; 610 updateBackground(); 611 } 612 break; 613 default: 614 throw new IllegalArgumentException("Invalid background type"); 615 } 616 } 617 618 /** 619 * Returns the background type. 620 */ 621 public int getBackgroundType() { 622 return mBackgroundType; 623 } 624 625 private void updateBackground() { 626 if (mRootView != null) { 627 int color = mBgDarkColor; 628 switch (mBackgroundType) { 629 case BG_DARK: break; 630 case BG_LIGHT: color = mBgLightColor; break; 631 case BG_NONE: color = Color.TRANSPARENT; break; 632 } 633 mRootView.setBackground(new ColorDrawable(color)); 634 } 635 } 636 637 private void updateControlsBottomSpace(ItemBridgeAdapter.ViewHolder vh) { 638 // Add extra space between rows 0 and 1 639 if (vh == null && getVerticalGridView() != null) { 640 vh = (ItemBridgeAdapter.ViewHolder) 641 getVerticalGridView().findViewHolderForPosition(0); 642 } 643 if (vh != null && vh.getPresenter() instanceof PlaybackControlsRowPresenter) { 644 final int adapterSize = getAdapter() == null ? 0 : getAdapter().size(); 645 ((PlaybackControlsRowPresenter) vh.getPresenter()).showBottomSpace( 646 (PlaybackControlsRowPresenter.ViewHolder) vh.getViewHolder(), 647 adapterSize > 1); 648 } 649 } 650 651 private final ItemBridgeAdapter.AdapterListener mAdapterListener = 652 new ItemBridgeAdapter.AdapterListener() { 653 @Override 654 public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder vh) { 655 if (DEBUG) Log.v(TAG, "onAttachedToWindow " + vh.getViewHolder().view); 656 if ((mFadingStatus == IDLE && mBgAlpha == 0) || mFadingStatus == OUT) { 657 if (DEBUG) Log.v(TAG, "setting alpha to 0"); 658 vh.getViewHolder().view.setAlpha(0); 659 } 660 if (vh.getPosition() == 0 && mResetControlsToPrimaryActionsPending) { 661 resetControlsToPrimaryActions(vh); 662 } 663 } 664 @Override 665 public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder vh) { 666 if (DEBUG) Log.v(TAG, "onDetachedFromWindow " + vh.getViewHolder().view); 667 // Reset animation state 668 vh.getViewHolder().view.setAlpha(1f); 669 vh.getViewHolder().view.setTranslationY(0); 670 if (vh.getViewHolder() instanceof PlaybackControlsRowPresenter.ViewHolder) { 671 Presenter.ViewHolder descriptionVh = ((PlaybackControlsRowPresenter.ViewHolder) 672 vh.getViewHolder()).mDescriptionViewHolder; 673 if (descriptionVh != null) { 674 descriptionVh.view.setAlpha(1f); 675 } 676 } 677 } 678 @Override 679 public void onBind(ItemBridgeAdapter.ViewHolder vh) { 680 if (vh.getPosition() == 0) { 681 updateControlsBottomSpace(vh); 682 } 683 } 684 }; 685 686 @Override 687 public View onCreateView(LayoutInflater inflater, ViewGroup container, 688 Bundle savedInstanceState) { 689 mRootView = super.onCreateView(inflater, container, savedInstanceState); 690 mBgAlpha = 255; 691 updateBackground(); 692 getRowsFragment().setExternalAdapterListener(mAdapterListener); 693 return mRootView; 694 } 695 696 @Override 697 public void onDestroyView() { 698 mRootView = null; 699 super.onDestroyView(); 700 } 701 702 private final DataObserver mObserver = new DataObserver() { 703 public void onChanged() { 704 updateControlsBottomSpace(null); 705 } 706 }; 707 708 static abstract class AnimatorListener implements Animator.AnimatorListener { 709 ArrayList<View> mViews = new ArrayList<View>(); 710 ArrayList<Integer> mLayerType = new ArrayList<Integer>(); 711 712 public void onAnimationCancel(Animator animation) { 713 } 714 public void onAnimationRepeat(Animator animation) { 715 } 716 public void onAnimationStart(Animator animation) { 717 getViews(mViews); 718 for (View view : mViews) { 719 mLayerType.add(view.getLayerType()); 720 view.setLayerType(View.LAYER_TYPE_HARDWARE, null); 721 } 722 } 723 public void onAnimationEnd(Animator animation) { 724 for (int i = 0; i < mViews.size(); i++) { 725 mViews.get(i).setLayerType(mLayerType.get(i), null); 726 } 727 mLayerType.clear(); 728 mViews.clear(); 729 } 730 abstract void getViews(ArrayList<View> views); 731 }; 732} 733