PlaybackOverlayFragment.java revision 8f5c183ba7b9df6b5339586f51219b4d5e6305f3
17ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout/*
27ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout * Copyright (C) 2014 The Android Open Source Project
37ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout *
47ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
57ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout * in compliance with the License. You may obtain a copy of the License at
67ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout *
77ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout * http://www.apache.org/licenses/LICENSE-2.0
87ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout *
97ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout * Unless required by applicable law or agreed to in writing, software distributed under the License
107ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
117ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout * or implied. See the License for the specific language governing permissions and limitations under
127ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout * the License.
137ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout */
147ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stoutpackage android.support.v17.leanback.app;
157ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout
167709709c2c78490a21311e9950d5dca7e89a6aedCraig Stoutimport android.graphics.Color;
177709709c2c78490a21311e9950d5dca7e89a6aedCraig Stoutimport android.graphics.drawable.ColorDrawable;
18372d07bb41510d91a6a662a1906aceb0ee759481Craig Stoutimport android.animation.Animator;
19d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stoutimport android.animation.AnimatorInflater;
20d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stoutimport android.animation.TimeInterpolator;
21d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stoutimport android.animation.ValueAnimator;
226b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stoutimport android.view.animation.AccelerateInterpolator;
23d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stoutimport android.animation.ValueAnimator.AnimatorUpdateListener;
24d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stoutimport android.content.Context;
257ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stoutimport android.os.Bundle;
26372d07bb41510d91a6a662a1906aceb0ee759481Craig Stoutimport android.os.Handler;
27372d07bb41510d91a6a662a1906aceb0ee759481Craig Stoutimport android.os.Message;
28d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stoutimport android.support.v7.widget.RecyclerView;
297ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stoutimport android.support.v17.leanback.R;
30d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stoutimport android.support.v17.leanback.animation.LogAccelerateInterpolator;
31d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stoutimport android.support.v17.leanback.animation.LogDecelerateInterpolator;
326b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stoutimport android.support.v17.leanback.widget.Presenter;
33d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stoutimport android.support.v17.leanback.widget.ItemBridgeAdapter;
347ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stoutimport android.support.v17.leanback.widget.ObjectAdapter;
356dca725412977bb56b933bdec120e31909233cdbCraig Stoutimport android.support.v17.leanback.widget.ObjectAdapter.DataObserver;
367ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stoutimport android.support.v17.leanback.widget.VerticalGridView;
376b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stoutimport android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
38372d07bb41510d91a6a662a1906aceb0ee759481Craig Stoutimport android.util.Log;
39372d07bb41510d91a6a662a1906aceb0ee759481Craig Stoutimport android.view.KeyEvent;
407709709c2c78490a21311e9950d5dca7e89a6aedCraig Stoutimport android.view.LayoutInflater;
41372d07bb41510d91a6a662a1906aceb0ee759481Craig Stoutimport android.view.MotionEvent;
427709709c2c78490a21311e9950d5dca7e89a6aedCraig Stoutimport android.view.View;
437709709c2c78490a21311e9950d5dca7e89a6aedCraig Stoutimport android.view.ViewGroup;
44d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stoutimport android.view.ViewGroup.MarginLayoutParams;
45372d07bb41510d91a6a662a1906aceb0ee759481Craig Stoutimport android.view.animation.Interpolator;
46372d07bb41510d91a6a662a1906aceb0ee759481Craig Stoutimport android.view.animation.LinearInterpolator;
477ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout
487ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout
497ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout/**
507ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout * A fragment for displaying playback controls and related content.
516dca725412977bb56b933bdec120e31909233cdbCraig Stout * The {@link android.support.v17.leanback.widget.PlaybackControlsRow} is expected to be
526dca725412977bb56b933bdec120e31909233cdbCraig Stout * at position 0 in the adapter.
537ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout */
547ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stoutpublic class PlaybackOverlayFragment extends DetailsFragment {
557ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout
567709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    /**
577709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     * No background.
587709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     */
597709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    public static final int BG_NONE = 0;
607709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout
617709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    /**
627709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     * A dark translucent background.
637709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     */
647709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    public static final int BG_DARK = 1;
657709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout
667709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    /**
677709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     * A light translucent background.
687709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     */
697709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    public static final int BG_LIGHT = 2;
707709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout
71372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    public static class OnFadeCompleteListener {
72372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public void onFadeInComplete() {
73372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
74372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public void onFadeOutComplete() {
75372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
76372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
77372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
78372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private static final String TAG = "PlaybackOverlayFragment";
79372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private static final boolean DEBUG = false;
80d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private static final int ANIMATION_MULTIPLIER = 1;
81372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
82372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private static int START_FADE_OUT = 1;
83372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
84372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    // Fading status
85372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private static final int IDLE = 0;
86372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private static final int IN = 1;
87372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private static final int OUT = 2;
88372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
897ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    private int mAlignPosition;
90d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout    private int mPaddingBottom;
917709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    private View mRootView;
927709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    private int mBackgroundType = BG_DARK;
937709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    private int mBgDarkColor;
947709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    private int mBgLightColor;
95372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private int mShowTimeMs;
966b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout    private int mMajorFadeTranslateY, mMinorFadeTranslateY;
976b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout    private int mAnimationTranslateY;
98372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private OnFadeCompleteListener mFadeCompleteListener;
99372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private boolean mFadingEnabled = true;
100372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private int mFadingStatus = IDLE;
101d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private int mBgAlpha;
102d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private ValueAnimator mBgFadeInAnimator, mBgFadeOutAnimator;
103d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private ValueAnimator mControlRowFadeInAnimator, mControlRowFadeOutAnimator;
1046b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout    private ValueAnimator mDescriptionFadeInAnimator, mDescriptionFadeOutAnimator;
105d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private ValueAnimator mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator;
106d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private boolean mTranslateAnimationEnabled;
107aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout    private boolean mResetControlsToPrimaryActionsPending;
108d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private RecyclerView.ItemAnimator mItemAnimator;
109372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
110372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private final Animator.AnimatorListener mFadeListener =
111372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            new Animator.AnimatorListener() {
112372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        @Override
113372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public void onAnimationStart(Animator animation) {
114d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            enableVerticalGridAnimations(false);
115372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
116372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        @Override
117372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public void onAnimationRepeat(Animator animation) {
118372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
119372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        @Override
120372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public void onAnimationCancel(Animator animation) {
121372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
122372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        @Override
123372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public void onAnimationEnd(Animator animation) {
124d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (DEBUG) Log.v(TAG, "onAnimationEnd " + mBgAlpha);
125d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (mBgAlpha > 0) {
126d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                enableVerticalGridAnimations(true);
127372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                startFadeTimer();
128372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                if (mFadeCompleteListener != null) {
129372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                    mFadeCompleteListener.onFadeInComplete();
130372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                }
131d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            } else {
1321e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                if (getVerticalGridView() != null) {
1331e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                    // Reset focus to the controls row
1341e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                    getVerticalGridView().setSelectedPosition(0);
135aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout                    resetControlsToPrimaryActions(null);
1361e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                }
137d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                if (mFadeCompleteListener != null) {
138d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                    mFadeCompleteListener.onFadeOutComplete();
139d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                }
140372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            }
141372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            mFadingStatus = IDLE;
142372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
143372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    };
144372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
145372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private final Handler mHandler = new Handler() {
146372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        @Override
147372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public void handleMessage(Message message) {
148372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            if (message.what == START_FADE_OUT && mFadingEnabled) {
149372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                fade(false);
150372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            }
151372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
152372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    };
153372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
154372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private final VerticalGridView.OnTouchInterceptListener mOnTouchInterceptListener =
155372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            new VerticalGridView.OnTouchInterceptListener() {
156372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public boolean onInterceptTouchEvent(MotionEvent event) {
157372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            return onInterceptInputEvent();
158372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
159372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    };
160372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
161372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private final VerticalGridView.OnMotionInterceptListener mOnMotionInterceptListener =
162372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            new VerticalGridView.OnMotionInterceptListener() {
163372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public boolean onInterceptMotionEvent(MotionEvent event) {
164372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            return onInterceptInputEvent();
165372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
166372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    };
167372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
168372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private final VerticalGridView.OnKeyInterceptListener mOnKeyInterceptListener =
169372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            new VerticalGridView.OnKeyInterceptListener() {
170372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public boolean onInterceptKeyEvent(KeyEvent event) {
171372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            return onInterceptInputEvent();
172372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
173372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    };
174372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
175d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private void setBgAlpha(int alpha) {
176d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgAlpha = alpha;
1771e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout        if (mRootView != null) {
1781e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout            mRootView.getBackground().setAlpha(alpha);
1791e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout        }
180d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    }
181d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
182d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private void enableVerticalGridAnimations(boolean enable) {
183aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout        if (getVerticalGridView() != null) {
184aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout            getVerticalGridView().setAnimateChildLayout(enable);
185aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout        }
186aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout    }
187aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout
188aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout    private void resetControlsToPrimaryActions(ItemBridgeAdapter.ViewHolder vh) {
189aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout        if (vh == null && getVerticalGridView() != null) {
190aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout            vh = (ItemBridgeAdapter.ViewHolder) getVerticalGridView().findViewHolderForPosition(0);
1911e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout        }
192aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout        if (vh == null) {
193aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout            mResetControlsToPrimaryActionsPending = true;
194aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout        } else if (vh.getPresenter() instanceof PlaybackControlsRowPresenter) {
195aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout            mResetControlsToPrimaryActionsPending = false;
196aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout            ((PlaybackControlsRowPresenter) vh.getPresenter()).showPrimaryActions(
197aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout                    (PlaybackControlsRowPresenter.ViewHolder) vh.getViewHolder());
198d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        }
199d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    }
200d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
201372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    /**
202372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * Enables or disables view fading.  If enabled,
203372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * the view will be faded in when the fragment starts,
204372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * and will fade out after a time period.  The timeout
205372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * period is reset each time {@link #tickle} is called.
206372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     *
207372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     */
208372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    public void setFadingEnabled(boolean enabled) {
209372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (DEBUG) Log.v(TAG, "setFadingEnabled " + enabled);
210372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (enabled != mFadingEnabled) {
211372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            mFadingEnabled = enabled;
212372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            if (isResumed()) {
213372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                if (mFadingEnabled) {
214372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                    if (mFadingStatus == IDLE && !mHandler.hasMessages(START_FADE_OUT)) {
215372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                        startFadeTimer();
216372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                    }
217372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                } else {
218372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                    // Ensure fully opaque
219372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                    mHandler.removeMessages(START_FADE_OUT);
220372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                    fade(true);
221372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                }
222372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            }
223372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
224372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
225372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
226372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    /**
227372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * Returns true if view fading is enabled.
228372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     */
229372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    public boolean isFadingEnabled() {
230372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        return mFadingEnabled;
231372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
232372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
233372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    /**
234372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * Sets the listener to be called when fade in or out has completed.
235372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     */
236372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    public void setFadeCompleteListener(OnFadeCompleteListener listener) {
237372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        mFadeCompleteListener = listener;
238372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
239372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
240372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    /**
241372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * Returns the listener to be called when fade in or out has completed.
242372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     */
243372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    public OnFadeCompleteListener getFadeCompleteListener() {
244372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        return mFadeCompleteListener;
245372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
246372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
247372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    /**
248372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * Tickles the playback controls.  Fades in the view if it was faded out,
249372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * otherwise resets the fade out timer.  Tickling on input events is handled
250372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * by the fragment.
251372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     */
252372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    public void tickle() {
253372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (DEBUG) Log.v(TAG, "tickle enabled " + mFadingEnabled + " isResumed " + isResumed());
254372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (!mFadingEnabled || !isResumed()) {
255372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            return;
256372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
257372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (mHandler.hasMessages(START_FADE_OUT)) {
258372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            // Restart the timer
259372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            startFadeTimer();
260372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        } else {
261372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            fade(true);
262372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
263372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
264372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
265372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private boolean onInterceptInputEvent() {
266d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        if (DEBUG) Log.v(TAG, "onInterceptInputEvent status " + mFadingStatus);
267d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        boolean consumeEvent = (mFadingStatus == IDLE && mBgAlpha == 0);
268372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        tickle();
269372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        return consumeEvent;
270372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
271372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
272372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    @Override
273372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    public void onResume() {
274372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        super.onResume();
275372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (mFadingEnabled) {
276d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            setBgAlpha(0);
277372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            fade(true);
278372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
279372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        getVerticalGridView().setOnTouchInterceptListener(mOnTouchInterceptListener);
280372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        getVerticalGridView().setOnMotionInterceptListener(mOnMotionInterceptListener);
281372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        getVerticalGridView().setOnKeyInterceptListener(mOnKeyInterceptListener);
282372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
283372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
284372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private void startFadeTimer() {
2851e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout        if (mHandler != null) {
2861e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout            mHandler.removeMessages(START_FADE_OUT);
2871e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout            mHandler.sendEmptyMessageDelayed(START_FADE_OUT, mShowTimeMs);
2881e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout        }
289372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
290372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
291d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private static ValueAnimator loadAnimator(Context context, int resId) {
292d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(context, resId);
293d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        animator.setDuration(animator.getDuration() * ANIMATION_MULTIPLIER);
294d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        return animator;
295d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    }
296d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
297d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private void loadBgAnimator() {
298d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
299d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            @Override
300d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            public void onAnimationUpdate(ValueAnimator arg0) {
301d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                setBgAlpha((Integer) arg0.getAnimatedValue());
302d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            }
303d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        };
304d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
305d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgFadeInAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_in);
306d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgFadeInAnimator.addUpdateListener(listener);
307d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgFadeInAnimator.addListener(mFadeListener);
308d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
309d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgFadeOutAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_out);
310d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgFadeOutAnimator.addUpdateListener(listener);
311d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgFadeOutAnimator.addListener(mFadeListener);
312d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    }
313d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
314d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private TimeInterpolator mLogDecelerateInterpolator = new LogDecelerateInterpolator(100,0);
315d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private TimeInterpolator mLogAccelerateInterpolator = new LogAccelerateInterpolator(100,0);
316d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
317d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private void loadControlRowAnimator() {
318d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
319d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            @Override
320d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            public void onAnimationUpdate(ValueAnimator arg0) {
3211e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                if (getVerticalGridView() == null) {
3221e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                    return;
3231e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                }
324d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                RecyclerView.ViewHolder vh = getVerticalGridView().findViewHolderForPosition(0);
325d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                if (vh != null) {
326d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                    final float fraction = (Float) arg0.getAnimatedValue();
327d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                    if (DEBUG) Log.v(TAG, "fraction " + fraction);
328d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                    vh.itemView.setAlpha(fraction);
3296b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                    vh.itemView.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
330d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                }
331d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            }
332d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        };
333d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
334d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mControlRowFadeInAnimator = loadAnimator(
335d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                getActivity(), R.animator.lb_playback_controls_fade_in);
336d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mControlRowFadeInAnimator.addUpdateListener(listener);
337d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
338d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
339d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mControlRowFadeOutAnimator = loadAnimator(
340d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                getActivity(), R.animator.lb_playback_controls_fade_out);
341d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mControlRowFadeOutAnimator.addUpdateListener(listener);
342d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator);
343d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    }
344d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
345d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private void loadOtherRowAnimator() {
346d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
347d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            @Override
348d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            public void onAnimationUpdate(ValueAnimator arg0) {
3491e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                if (getVerticalGridView() == null) {
3501e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                    return;
3511e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                }
352d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                final float fraction = (Float) arg0.getAnimatedValue();
353d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                final int count = getVerticalGridView().getChildCount();
354d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                for (int i = 0; i < count; i++) {
355d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                    View view = getVerticalGridView().getChildAt(i);
356d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                    if (getVerticalGridView().getChildPosition(view) > 0) {
357d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                        view.setAlpha(fraction);
3586b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                        view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
359d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                    }
360d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                }
361d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            }
362d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        };
363d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
364d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mOtherRowFadeInAnimator = loadAnimator(
365d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                getActivity(), R.animator.lb_playback_controls_fade_in);
366d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mOtherRowFadeInAnimator.addUpdateListener(listener);
367d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
368d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
369d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mOtherRowFadeOutAnimator = loadAnimator(
370d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                getActivity(), R.animator.lb_playback_controls_fade_out);
371d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mOtherRowFadeOutAnimator.addUpdateListener(listener);
3726b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator());
3736b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout    }
3746b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout
3756b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout    private void loadDescriptionAnimator() {
3766b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
3776b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout            @Override
3786b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout            public void onAnimationUpdate(ValueAnimator arg0) {
3796b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                if (getVerticalGridView() == null) {
3806b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                    return;
3816b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                }
3826b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                ItemBridgeAdapter.ViewHolder adapterVh = (ItemBridgeAdapter.ViewHolder)
3836b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                        getVerticalGridView().findViewHolderForPosition(0);
3846b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                if (adapterVh != null && adapterVh.getViewHolder()
3856b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                        instanceof PlaybackControlsRowPresenter.ViewHolder) {
3866b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                    final Presenter.ViewHolder vh = ((PlaybackControlsRowPresenter.ViewHolder)
3876b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                            adapterVh.getViewHolder()).mDescriptionViewHolder;
3888f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                    if (vh != null) {
3898f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                        vh.view.setAlpha((Float) arg0.getAnimatedValue());
3908f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                    }
3916b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                }
3926b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout            }
3936b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        };
3946b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout
3956b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mDescriptionFadeInAnimator = loadAnimator(
3966b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                getActivity(), R.animator.lb_playback_description_fade_in);
3976b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mDescriptionFadeInAnimator.addUpdateListener(listener);
3986b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mDescriptionFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
3996b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout
4006b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mDescriptionFadeOutAnimator = loadAnimator(
4016b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                getActivity(), R.animator.lb_playback_description_fade_out);
4026b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mDescriptionFadeOutAnimator.addUpdateListener(listener);
403d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    }
404d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
405372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private void fade(boolean fadeIn) {
406372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (DEBUG) Log.v(TAG, "fade " + fadeIn);
407372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (getView() == null) {
408372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            return;
409372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
410372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if ((fadeIn && mFadingStatus == IN) || (!fadeIn && mFadingStatus == OUT)) {
411d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (DEBUG) Log.v(TAG, "requested fade in progress");
412d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            return;
413d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        }
414d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        if ((fadeIn && mBgAlpha == 255) || (!fadeIn && mBgAlpha == 0)) {
415d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (DEBUG) Log.v(TAG, "fade is no-op");
416372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            return;
417372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
418372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
4196b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mAnimationTranslateY = getVerticalGridView().getSelectedPosition() == 0 ?
4206b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                mMajorFadeTranslateY : mMinorFadeTranslateY;
421d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
422d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        if (mFadingStatus == IDLE) {
423d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (fadeIn) {
424d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mBgFadeInAnimator.start();
425d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mControlRowFadeInAnimator.start();
426d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mOtherRowFadeInAnimator.start();
4276b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                mDescriptionFadeInAnimator.start();
428d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            } else {
429d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mBgFadeOutAnimator.start();
430d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mControlRowFadeOutAnimator.start();
431d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mOtherRowFadeOutAnimator.start();
4326b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                mDescriptionFadeOutAnimator.start();
433d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            }
434d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        } else {
435d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (fadeIn) {
436d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mBgFadeOutAnimator.reverse();
437d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mControlRowFadeOutAnimator.reverse();
438d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mOtherRowFadeOutAnimator.reverse();
4396b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                mDescriptionFadeOutAnimator.reverse();
440d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            } else {
441d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mBgFadeInAnimator.reverse();
442d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mControlRowFadeInAnimator.reverse();
443d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mOtherRowFadeInAnimator.reverse();
4446b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                mDescriptionFadeInAnimator.reverse();
445d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            }
446d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        }
447d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
448d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        // If fading in while control row is focused, set initial translationY so
449d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        // views slide in from below.
4506b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        if (fadeIn && mFadingStatus == IDLE) {
451d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            final int count = getVerticalGridView().getChildCount();
452d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            for (int i = 0; i < count; i++) {
4536b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                getVerticalGridView().getChildAt(i).setTranslationY(mAnimationTranslateY);
454d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            }
455d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        }
456d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
457372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        mFadingStatus = fadeIn ? IN : OUT;
458372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
4597ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout
4607ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    /**
4617ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout     * Sets the list of rows for the fragment.
4627ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout     */
4637ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    @Override
4647ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    public void setAdapter(ObjectAdapter adapter) {
4656dca725412977bb56b933bdec120e31909233cdbCraig Stout        if (getAdapter() != null) {
4666dca725412977bb56b933bdec120e31909233cdbCraig Stout            getAdapter().unregisterObserver(mObserver);
4676dca725412977bb56b933bdec120e31909233cdbCraig Stout        }
4687ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        super.setAdapter(adapter);
4696dca725412977bb56b933bdec120e31909233cdbCraig Stout        if (adapter != null) {
4706dca725412977bb56b933bdec120e31909233cdbCraig Stout            adapter.registerObserver(mObserver);
4716dca725412977bb56b933bdec120e31909233cdbCraig Stout        }
4727ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    }
4737ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout
4747ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    @Override
4757ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    void setVerticalGridViewLayout(VerticalGridView listview) {
476d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        if (listview == null) {
4777ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout            return;
4787ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        }
479d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        // Padding affects alignment when last row is focused
480d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        // (last is first when there's only one row).
481d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        setBottomPadding(listview, mPaddingBottom);
482d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout
483d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        // Item alignment affects focused row that isn't the last.
484d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        listview.setItemAlignmentOffset(mAlignPosition);
4857ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        listview.setItemAlignmentOffsetPercent(100);
486d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout
487d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        // Push rows to the bottom.
4887ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        listview.setWindowAlignmentOffset(0);
4897ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        listview.setWindowAlignmentOffsetPercent(100);
4907ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE);
4917ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    }
4927ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout
493d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout    private static void setBottomPadding(View view, int padding) {
494d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        view.setPadding(view.getPaddingLeft(), view.getPaddingTop(),
495d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout                view.getPaddingRight(), padding);
496d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout    }
497d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout
4987ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    @Override
4997ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    public void onCreate(Bundle savedInstanceState) {
5007ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        super.onCreate(savedInstanceState);
5017ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout
5027ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        mAlignPosition =
503d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_align_bottom);
504d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        mPaddingBottom =
505d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom);
5067709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        mBgDarkColor =
5077709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout                getResources().getColor(R.color.lb_playback_controls_background_dark);
5087709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        mBgLightColor =
5097709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout                getResources().getColor(R.color.lb_playback_controls_background_light);
510372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        mShowTimeMs =
511372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                getResources().getInteger(R.integer.lb_playback_controls_show_time_ms);
5126b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mMajorFadeTranslateY =
5136b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                getResources().getDimensionPixelSize(R.dimen.lb_playback_major_fade_translate_y);
5146b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mMinorFadeTranslateY =
5156b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                getResources().getDimensionPixelSize(R.dimen.lb_playback_minor_fade_translate_y);
516d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
517d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        loadBgAnimator();
518d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        loadControlRowAnimator();
519d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        loadOtherRowAnimator();
5206b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        loadDescriptionAnimator();
5217709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    }
5227709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout
5237709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    /**
5247709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     * Sets the background type.
5257709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     *
5267709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     * @param type One of BG_LIGHT, BG_DARK, or BG_NONE.
5277709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     */
5287709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    public void setBackgroundType(int type) {
529372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        switch (type) {
530372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        case BG_LIGHT:
531372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        case BG_DARK:
532372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        case BG_NONE:
533372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            if (type != mBackgroundType) {
534372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                mBackgroundType = type;
535372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                updateBackground();
536372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            }
537372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            break;
538372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        default:
5397709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout            throw new IllegalArgumentException("Invalid background type");
5407709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        }
5417709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    }
5427709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout
5437709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    /**
5447709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     * Returns the background type.
5457709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     */
5467709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    public int getBackgroundType() {
5477709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        return mBackgroundType;
5487709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    }
5497709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout
5507709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    private void updateBackground() {
5517709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        if (mRootView != null) {
5527709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout            int color = mBgDarkColor;
5537709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout            switch (mBackgroundType) {
5547709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout                case BG_DARK: break;
5557709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout                case BG_LIGHT: color = mBgLightColor; break;
5567709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout                case BG_NONE: color = Color.TRANSPARENT; break;
5577709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout            }
5587709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout            mRootView.setBackground(new ColorDrawable(color));
5597709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        }
5607709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    }
5617709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout
562d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout    private void updateControlsBottomSpace(ItemBridgeAdapter.ViewHolder vh) {
563d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        // Add extra space between rows 0 and 1
564d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        if (vh == null && getVerticalGridView() != null) {
565d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout            vh = (ItemBridgeAdapter.ViewHolder)
566d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout                    getVerticalGridView().findViewHolderForPosition(0);
567d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        }
568d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        if (vh != null && vh.getPresenter() instanceof PlaybackControlsRowPresenter) {
569d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout            final int adapterSize = getAdapter() == null ? 0 : getAdapter().size();
570d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout            ((PlaybackControlsRowPresenter) vh.getPresenter()).showBottomSpace(
571d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout                    (PlaybackControlsRowPresenter.ViewHolder) vh.getViewHolder(),
572d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout                    adapterSize > 1);
573d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        }
574d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout    }
575d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout
576d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private final ItemBridgeAdapter.AdapterListener mAdapterListener =
577d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            new ItemBridgeAdapter.AdapterListener() {
578d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        @Override
579d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder vh) {
580d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (DEBUG) Log.v(TAG, "onAttachedToWindow " + vh.getViewHolder().view);
581d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if ((mFadingStatus == IDLE && mBgAlpha == 0) || mFadingStatus == OUT) {
582d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                if (DEBUG) Log.v(TAG, "setting alpha to 0");
583d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                vh.getViewHolder().view.setAlpha(0);
584d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            }
585aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout            if (vh.getPosition() == 0 && mResetControlsToPrimaryActionsPending) {
586aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout                resetControlsToPrimaryActions(vh);
587aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout            }
588d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        }
589d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        @Override
590d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder vh) {
591d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (DEBUG) Log.v(TAG, "onDetachedFromWindow " + vh.getViewHolder().view);
592d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            // Reset animation state
593d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            vh.getViewHolder().view.setAlpha(1f);
594d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            vh.getViewHolder().view.setTranslationY(0);
5956b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout            if (vh.getViewHolder() instanceof PlaybackControlsRowPresenter.ViewHolder) {
5968f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                Presenter.ViewHolder descriptionVh = ((PlaybackControlsRowPresenter.ViewHolder)
5978f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                        vh.getViewHolder()).mDescriptionViewHolder;
5988f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                if (descriptionVh != null) {
5998f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                    descriptionVh.view.setAlpha(1f);
6008f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                }
6016b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout            }
602d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        }
603d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        @Override
604d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        public void onBind(ItemBridgeAdapter.ViewHolder vh) {
605d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout            if (vh.getPosition() == 0) {
606d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout                updateControlsBottomSpace(vh);
607d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout            }
608d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        }
609d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    };
610d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
6117709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    @Override
6127709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    public View onCreateView(LayoutInflater inflater, ViewGroup container,
6137709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout            Bundle savedInstanceState) {
6147709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        mRootView = super.onCreateView(inflater, container, savedInstanceState);
615d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgAlpha = 255;
6167709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        updateBackground();
617d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        getRowsFragment().setExternalAdapterListener(mAdapterListener);
6187709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        return mRootView;
6197ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    }
6206dca725412977bb56b933bdec120e31909233cdbCraig Stout
6211e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout    @Override
6221e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout    public void onDestroyView() {
6231e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout        mRootView = null;
6241e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout        super.onDestroyView();
6251e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout    }
6261e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout
6276dca725412977bb56b933bdec120e31909233cdbCraig Stout    private final DataObserver mObserver = new DataObserver() {
6286dca725412977bb56b933bdec120e31909233cdbCraig Stout        public void onChanged() {
629d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout            updateControlsBottomSpace(null);
6306dca725412977bb56b933bdec120e31909233cdbCraig Stout        }
6316dca725412977bb56b933bdec120e31909233cdbCraig Stout    };
6327ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout}
633