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