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