PlaybackOverlayFragment.java revision c92c356de1a687598a031f3452053dc6c9af9b77
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;
22cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stoutimport android.view.InputEvent;
236b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stoutimport android.view.animation.AccelerateInterpolator;
24d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stoutimport android.animation.ValueAnimator.AnimatorUpdateListener;
25d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stoutimport android.content.Context;
267ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stoutimport android.os.Bundle;
27372d07bb41510d91a6a662a1906aceb0ee759481Craig Stoutimport android.os.Handler;
28372d07bb41510d91a6a662a1906aceb0ee759481Craig Stoutimport android.os.Message;
29d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stoutimport android.support.v7.widget.RecyclerView;
307ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stoutimport android.support.v17.leanback.R;
31d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stoutimport android.support.v17.leanback.animation.LogAccelerateInterpolator;
32d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stoutimport android.support.v17.leanback.animation.LogDecelerateInterpolator;
336b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stoutimport android.support.v17.leanback.widget.Presenter;
34d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stoutimport android.support.v17.leanback.widget.ItemBridgeAdapter;
357ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stoutimport android.support.v17.leanback.widget.ObjectAdapter;
366dca725412977bb56b933bdec120e31909233cdbCraig Stoutimport android.support.v17.leanback.widget.ObjectAdapter.DataObserver;
377ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stoutimport android.support.v17.leanback.widget.VerticalGridView;
386b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stoutimport android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
39372d07bb41510d91a6a662a1906aceb0ee759481Craig Stoutimport android.util.Log;
40372d07bb41510d91a6a662a1906aceb0ee759481Craig Stoutimport android.view.KeyEvent;
417709709c2c78490a21311e9950d5dca7e89a6aedCraig Stoutimport android.view.LayoutInflater;
42372d07bb41510d91a6a662a1906aceb0ee759481Craig Stoutimport android.view.MotionEvent;
437709709c2c78490a21311e9950d5dca7e89a6aedCraig Stoutimport android.view.View;
447709709c2c78490a21311e9950d5dca7e89a6aedCraig Stoutimport android.view.ViewGroup;
457ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout
462d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stoutimport java.util.ArrayList;
477ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout
487ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout/**
497ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout * A fragment for displaying playback controls and related content.
506dca725412977bb56b933bdec120e31909233cdbCraig Stout * The {@link android.support.v17.leanback.widget.PlaybackControlsRow} is expected to be
516dca725412977bb56b933bdec120e31909233cdbCraig Stout * at position 0 in the adapter.
527ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout */
537ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stoutpublic class PlaybackOverlayFragment extends DetailsFragment {
547ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout
557709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    /**
567709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     * No background.
577709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     */
587709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    public static final int BG_NONE = 0;
597709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout
607709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    /**
617709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     * A dark translucent background.
627709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     */
637709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    public static final int BG_DARK = 1;
647709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout
657709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    /**
667709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     * A light translucent background.
677709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     */
687709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    public static final int BG_LIGHT = 2;
697709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout
70372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    public static class OnFadeCompleteListener {
71372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public void onFadeInComplete() {
72372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
73372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public void onFadeOutComplete() {
74372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
75372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
76372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
77eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout    public interface InputEventHandler {
78eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout        /**
79eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout         * Called when an {@link InputEvent} is received.
80eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout         *
81eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout         * @return If the event should be consumed, return true. To allow the event to
82eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout         * continue on to the next handler, return false.
83eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout         */
84eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout        public boolean handleInputEvent(InputEvent event);
85eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout    }
86eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout
87372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private static final String TAG = "PlaybackOverlayFragment";
88372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private static final boolean DEBUG = false;
89d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private static final int ANIMATION_MULTIPLIER = 1;
90372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
91372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private static int START_FADE_OUT = 1;
92372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
93372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    // Fading status
94372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private static final int IDLE = 0;
95372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private static final int IN = 1;
96372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private static final int OUT = 2;
97372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
987ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    private int mAlignPosition;
99d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout    private int mPaddingBottom;
1007709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    private View mRootView;
1017709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    private int mBackgroundType = BG_DARK;
1027709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    private int mBgDarkColor;
1037709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    private int mBgLightColor;
104372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private int mShowTimeMs;
1056b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout    private int mMajorFadeTranslateY, mMinorFadeTranslateY;
1066b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout    private int mAnimationTranslateY;
107372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private OnFadeCompleteListener mFadeCompleteListener;
108eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout    private InputEventHandler mInputEventHandler;
109372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private boolean mFadingEnabled = true;
110372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private int mFadingStatus = IDLE;
111d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private int mBgAlpha;
112d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private ValueAnimator mBgFadeInAnimator, mBgFadeOutAnimator;
113d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private ValueAnimator mControlRowFadeInAnimator, mControlRowFadeOutAnimator;
1146b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout    private ValueAnimator mDescriptionFadeInAnimator, mDescriptionFadeOutAnimator;
115d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private ValueAnimator mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator;
116d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private boolean mTranslateAnimationEnabled;
117aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout    private boolean mResetControlsToPrimaryActionsPending;
118d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private RecyclerView.ItemAnimator mItemAnimator;
119372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
120372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private final Animator.AnimatorListener mFadeListener =
121372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            new Animator.AnimatorListener() {
122372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        @Override
123372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public void onAnimationStart(Animator animation) {
124d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            enableVerticalGridAnimations(false);
125372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
126372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        @Override
127372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public void onAnimationRepeat(Animator animation) {
128372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
129372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        @Override
130372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public void onAnimationCancel(Animator animation) {
131372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
132372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        @Override
133372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public void onAnimationEnd(Animator animation) {
134d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (DEBUG) Log.v(TAG, "onAnimationEnd " + mBgAlpha);
135d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (mBgAlpha > 0) {
136d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                enableVerticalGridAnimations(true);
137372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                startFadeTimer();
138372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                if (mFadeCompleteListener != null) {
139372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                    mFadeCompleteListener.onFadeInComplete();
140372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                }
141d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            } else {
1421e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                if (getVerticalGridView() != null) {
1431e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                    // Reset focus to the controls row
1441e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                    getVerticalGridView().setSelectedPosition(0);
145aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout                    resetControlsToPrimaryActions(null);
1461e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                }
147d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                if (mFadeCompleteListener != null) {
148d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                    mFadeCompleteListener.onFadeOutComplete();
149d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                }
150372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            }
151372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            mFadingStatus = IDLE;
152372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
153372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    };
154372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
155372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private final Handler mHandler = new Handler() {
156372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        @Override
157372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public void handleMessage(Message message) {
158372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            if (message.what == START_FADE_OUT && mFadingEnabled) {
159372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                fade(false);
160372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            }
161372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
162372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    };
163372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
164372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private final VerticalGridView.OnTouchInterceptListener mOnTouchInterceptListener =
165372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            new VerticalGridView.OnTouchInterceptListener() {
166372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public boolean onInterceptTouchEvent(MotionEvent event) {
167cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout            return onInterceptInputEvent(event);
168372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
169372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    };
170372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
171372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private final VerticalGridView.OnMotionInterceptListener mOnMotionInterceptListener =
172372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            new VerticalGridView.OnMotionInterceptListener() {
173372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public boolean onInterceptMotionEvent(MotionEvent event) {
174cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout            return onInterceptInputEvent(event);
175372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
176372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    };
177372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
178372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private final VerticalGridView.OnKeyInterceptListener mOnKeyInterceptListener =
179372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            new VerticalGridView.OnKeyInterceptListener() {
180372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        public boolean onInterceptKeyEvent(KeyEvent event) {
181cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout            return onInterceptInputEvent(event);
182372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
183372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    };
184372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
185d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private void setBgAlpha(int alpha) {
186d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgAlpha = alpha;
1871e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout        if (mRootView != null) {
1881e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout            mRootView.getBackground().setAlpha(alpha);
1891e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout        }
190d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    }
191d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
192d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private void enableVerticalGridAnimations(boolean enable) {
193aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout        if (getVerticalGridView() != null) {
194aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout            getVerticalGridView().setAnimateChildLayout(enable);
195aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout        }
196aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout    }
197aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout
198aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout    private void resetControlsToPrimaryActions(ItemBridgeAdapter.ViewHolder vh) {
199aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout        if (vh == null && getVerticalGridView() != null) {
200aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout            vh = (ItemBridgeAdapter.ViewHolder) getVerticalGridView().findViewHolderForPosition(0);
2011e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout        }
202aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout        if (vh == null) {
203aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout            mResetControlsToPrimaryActionsPending = true;
204aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout        } else if (vh.getPresenter() instanceof PlaybackControlsRowPresenter) {
205aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout            mResetControlsToPrimaryActionsPending = false;
206aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout            ((PlaybackControlsRowPresenter) vh.getPresenter()).showPrimaryActions(
207aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout                    (PlaybackControlsRowPresenter.ViewHolder) vh.getViewHolder());
208d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        }
209d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    }
210d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
211372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    /**
212372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * Enables or disables view fading.  If enabled,
213372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * the view will be faded in when the fragment starts,
214372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * and will fade out after a time period.  The timeout
215372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * period is reset each time {@link #tickle} is called.
216372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     *
217372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     */
218372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    public void setFadingEnabled(boolean enabled) {
219372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (DEBUG) Log.v(TAG, "setFadingEnabled " + enabled);
220372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (enabled != mFadingEnabled) {
221372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            mFadingEnabled = enabled;
222f47fb1e34efd538c322f7539893272ba847cdbdcCraig Stout            if (mFadingEnabled) {
223f47fb1e34efd538c322f7539893272ba847cdbdcCraig Stout                if (isResumed() && mFadingStatus == IDLE
224f47fb1e34efd538c322f7539893272ba847cdbdcCraig Stout                        && !mHandler.hasMessages(START_FADE_OUT)) {
225f47fb1e34efd538c322f7539893272ba847cdbdcCraig Stout                    startFadeTimer();
226372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                }
227f47fb1e34efd538c322f7539893272ba847cdbdcCraig Stout            } else {
228f47fb1e34efd538c322f7539893272ba847cdbdcCraig Stout                // Ensure fully opaque
229f47fb1e34efd538c322f7539893272ba847cdbdcCraig Stout                mHandler.removeMessages(START_FADE_OUT);
230f47fb1e34efd538c322f7539893272ba847cdbdcCraig Stout                fade(true);
231372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            }
232372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
233372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
234372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
235372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    /**
236372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * Returns true if view fading is enabled.
237372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     */
238372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    public boolean isFadingEnabled() {
239372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        return mFadingEnabled;
240372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
241372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
242372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    /**
243372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * Sets the listener to be called when fade in or out has completed.
244372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     */
245372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    public void setFadeCompleteListener(OnFadeCompleteListener listener) {
246372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        mFadeCompleteListener = listener;
247372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
248372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
249372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    /**
250372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * Returns the listener to be called when fade in or out has completed.
251372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     */
252372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    public OnFadeCompleteListener getFadeCompleteListener() {
253372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        return mFadeCompleteListener;
254372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
255372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
256372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    /**
257eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout     * Sets the input event handler.
258eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout     */
259eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout    public final void setInputEventHandler(InputEventHandler handler) {
260eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout        mInputEventHandler = handler;
261eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout    }
262eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout
263eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout    /**
264eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout     * Returns the input event handler.
265eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout     */
2662dfed05c8ab53ca7c28424c9c03b1a87b9b7ca0dCraig Stout    public final InputEventHandler getInputEventHandler() {
267eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout        return mInputEventHandler;
268eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout    }
269eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout
270eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout    /**
271372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * Tickles the playback controls.  Fades in the view if it was faded out,
272372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * otherwise resets the fade out timer.  Tickling on input events is handled
273372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     * by the fragment.
274372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout     */
275372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    public void tickle() {
276372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (DEBUG) Log.v(TAG, "tickle enabled " + mFadingEnabled + " isResumed " + isResumed());
277372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (!mFadingEnabled || !isResumed()) {
278372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            return;
279372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
280372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (mHandler.hasMessages(START_FADE_OUT)) {
281372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            // Restart the timer
282372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            startFadeTimer();
283372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        } else {
284372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            fade(true);
285372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
286372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
287372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
288cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout    private static boolean isConsumableKey(KeyEvent keyEvent) {
289cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout        if (keyEvent.isSystem()) {
290cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout            return false;
291cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout        }
292cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout        return true;
293cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout    }
294cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout
295cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout    private boolean onInterceptInputEvent(InputEvent event) {
296c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout        if (DEBUG) Log.v(TAG, "onInterceptInputEvent status " + mFadingStatus +
297c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout                " mBgAlpha " + mBgAlpha + " event " + event);
298c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout        final boolean controlsHidden = (mFadingStatus == IDLE && mBgAlpha == 0);
299c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout        boolean consumeEvent = controlsHidden;
300c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout        int keyCode = KeyEvent.KEYCODE_UNKNOWN;
301c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout
302cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout        if (event instanceof KeyEvent) {
303cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout            if (consumeEvent) {
304cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout                consumeEvent = isConsumableKey((KeyEvent) event);
305cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout            }
306c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout            keyCode = ((KeyEvent) event).getKeyCode();
307c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout        }
308c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout        if (!consumeEvent && mInputEventHandler != null) {
309c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout            consumeEvent = mInputEventHandler.handleInputEvent(event);
310c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout        }
311c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout        if (keyCode == KeyEvent.KEYCODE_BACK) {
312c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout            // If fading enabled and controls are not hidden, back will be consumed to fade
313c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout            // them out (even if the key was consumed by the handler).
314c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout            if (mFadingEnabled && !controlsHidden) {
315c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout                consumeEvent = true;
316c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout                mHandler.removeMessages(START_FADE_OUT);
317c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout                fade(false);
318c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout            } else if (consumeEvent) {
319cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout                tickle();
320cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout            }
321cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout        } else {
322c92c356de1a687598a031f3452053dc6c9af9b77Craig Stout            // Any other key will show the controls
323cbfc318baee2fc054af4c723bfac0fd3c28a1667Craig Stout            tickle();
324eb66dab544c4c1eabe4d469b7cea348d4b01e664Craig Stout        }
325372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        return consumeEvent;
326372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
327372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
328372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    @Override
329372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    public void onResume() {
330372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        super.onResume();
331372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (mFadingEnabled) {
332d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            setBgAlpha(0);
333372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            fade(true);
334372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
335372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        getVerticalGridView().setOnTouchInterceptListener(mOnTouchInterceptListener);
336372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        getVerticalGridView().setOnMotionInterceptListener(mOnMotionInterceptListener);
337372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        getVerticalGridView().setOnKeyInterceptListener(mOnKeyInterceptListener);
338372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
339372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
340372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private void startFadeTimer() {
3411e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout        if (mHandler != null) {
3421e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout            mHandler.removeMessages(START_FADE_OUT);
3431e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout            mHandler.sendEmptyMessageDelayed(START_FADE_OUT, mShowTimeMs);
3441e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout        }
345372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
346372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
347d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private static ValueAnimator loadAnimator(Context context, int resId) {
348d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(context, resId);
349d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        animator.setDuration(animator.getDuration() * ANIMATION_MULTIPLIER);
350d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        return animator;
351d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    }
352d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
353d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private void loadBgAnimator() {
354d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
355d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            @Override
356d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            public void onAnimationUpdate(ValueAnimator arg0) {
357d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                setBgAlpha((Integer) arg0.getAnimatedValue());
358d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            }
359d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        };
360d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
361d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgFadeInAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_in);
362d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgFadeInAnimator.addUpdateListener(listener);
363d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgFadeInAnimator.addListener(mFadeListener);
364d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
365d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgFadeOutAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_out);
366d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgFadeOutAnimator.addUpdateListener(listener);
367d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgFadeOutAnimator.addListener(mFadeListener);
368d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    }
369d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
370d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private TimeInterpolator mLogDecelerateInterpolator = new LogDecelerateInterpolator(100,0);
371d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private TimeInterpolator mLogAccelerateInterpolator = new LogAccelerateInterpolator(100,0);
372d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
3732d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout    private View getControlRowView() {
3742d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        if (getVerticalGridView() == null) {
3752d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            return null;
3762d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        }
3772d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        RecyclerView.ViewHolder vh = getVerticalGridView().findViewHolderForPosition(0);
3782d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        if (vh == null) {
3792d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            return null;
3802d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        }
3812d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        return vh.itemView;
3822d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout    }
3832d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout
384d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private void loadControlRowAnimator() {
3852d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        final AnimatorListener listener = new AnimatorListener() {
386d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            @Override
3872d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            void getViews(ArrayList<View> views) {
3882d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                View view = getControlRowView();
3892d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                if (view != null) {
3902d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                    views.add(view);
3911e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                }
3922d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            }
3932d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        };
3942d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
3952d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            @Override
3962d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            public void onAnimationUpdate(ValueAnimator arg0) {
3972d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                View view = getControlRowView();
3982d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                if (view != null) {
399d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                    final float fraction = (Float) arg0.getAnimatedValue();
400d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                    if (DEBUG) Log.v(TAG, "fraction " + fraction);
4012d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                    view.setAlpha(fraction);
4022d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                    view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
403d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                }
404d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            }
405d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        };
406d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
407d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mControlRowFadeInAnimator = loadAnimator(
408d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                getActivity(), R.animator.lb_playback_controls_fade_in);
4092d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        mControlRowFadeInAnimator.addUpdateListener(updateListener);
4102d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        mControlRowFadeInAnimator.addListener(listener);
411d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
412d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
413d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mControlRowFadeOutAnimator = loadAnimator(
414d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                getActivity(), R.animator.lb_playback_controls_fade_out);
4152d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        mControlRowFadeOutAnimator.addUpdateListener(updateListener);
4162d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        mControlRowFadeOutAnimator.addListener(listener);
417d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator);
418d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    }
419d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
420d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private void loadOtherRowAnimator() {
4212d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        final AnimatorListener listener = new AnimatorListener() {
422d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            @Override
4232d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            void getViews(ArrayList<View> views) {
4241e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                if (getVerticalGridView() == null) {
4251e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                    return;
4261e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout                }
427d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                final int count = getVerticalGridView().getChildCount();
428d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                for (int i = 0; i < count; i++) {
429d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                    View view = getVerticalGridView().getChildAt(i);
4302d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                    if (view != null) {
4312d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                        views.add(view);
4322d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                    }
4332d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                }
4342d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            }
4352d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        };
4362d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
4372d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            @Override
4382d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            public void onAnimationUpdate(ValueAnimator arg0) {
4392d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                final float fraction = (Float) arg0.getAnimatedValue();
4402d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                for (View view : listener.mViews) {
441d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                    if (getVerticalGridView().getChildPosition(view) > 0) {
442d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                        view.setAlpha(fraction);
4436b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                        view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
444d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                    }
445d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                }
446d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            }
447d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        };
448d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
449d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mOtherRowFadeInAnimator = loadAnimator(
450d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                getActivity(), R.animator.lb_playback_controls_fade_in);
4512d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        mOtherRowFadeInAnimator.addListener(listener);
4522d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        mOtherRowFadeInAnimator.addUpdateListener(updateListener);
453d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
454d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
455d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mOtherRowFadeOutAnimator = loadAnimator(
456d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                getActivity(), R.animator.lb_playback_controls_fade_out);
4572d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        mOtherRowFadeOutAnimator.addListener(listener);
4582d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        mOtherRowFadeOutAnimator.addUpdateListener(updateListener);
4596b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator());
4606b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout    }
4616b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout
4626b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout    private void loadDescriptionAnimator() {
4636b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
4646b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout            @Override
4656b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout            public void onAnimationUpdate(ValueAnimator arg0) {
4666b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                if (getVerticalGridView() == null) {
4676b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                    return;
4686b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                }
4696b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                ItemBridgeAdapter.ViewHolder adapterVh = (ItemBridgeAdapter.ViewHolder)
4706b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                        getVerticalGridView().findViewHolderForPosition(0);
4716b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                if (adapterVh != null && adapterVh.getViewHolder()
4726b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                        instanceof PlaybackControlsRowPresenter.ViewHolder) {
4736b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                    final Presenter.ViewHolder vh = ((PlaybackControlsRowPresenter.ViewHolder)
4746b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                            adapterVh.getViewHolder()).mDescriptionViewHolder;
4758f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                    if (vh != null) {
4768f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                        vh.view.setAlpha((Float) arg0.getAnimatedValue());
4778f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                    }
4786b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                }
4796b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout            }
4806b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        };
4816b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout
4826b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mDescriptionFadeInAnimator = loadAnimator(
4836b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                getActivity(), R.animator.lb_playback_description_fade_in);
4846b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mDescriptionFadeInAnimator.addUpdateListener(listener);
4856b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mDescriptionFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
4866b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout
4876b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mDescriptionFadeOutAnimator = loadAnimator(
4886b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                getActivity(), R.animator.lb_playback_description_fade_out);
4896b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mDescriptionFadeOutAnimator.addUpdateListener(listener);
490d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    }
491d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
492372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    private void fade(boolean fadeIn) {
493372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (DEBUG) Log.v(TAG, "fade " + fadeIn);
494372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if (getView() == null) {
495372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            return;
496372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
497372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        if ((fadeIn && mFadingStatus == IN) || (!fadeIn && mFadingStatus == OUT)) {
498d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (DEBUG) Log.v(TAG, "requested fade in progress");
499d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            return;
500d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        }
501d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        if ((fadeIn && mBgAlpha == 255) || (!fadeIn && mBgAlpha == 0)) {
502d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (DEBUG) Log.v(TAG, "fade is no-op");
503372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            return;
504372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        }
505372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout
5066b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mAnimationTranslateY = getVerticalGridView().getSelectedPosition() == 0 ?
5076b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                mMajorFadeTranslateY : mMinorFadeTranslateY;
508d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
509d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        if (mFadingStatus == IDLE) {
510d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (fadeIn) {
511d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mBgFadeInAnimator.start();
512d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mControlRowFadeInAnimator.start();
513d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mOtherRowFadeInAnimator.start();
5146b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                mDescriptionFadeInAnimator.start();
515d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            } else {
516d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mBgFadeOutAnimator.start();
517d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mControlRowFadeOutAnimator.start();
518d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mOtherRowFadeOutAnimator.start();
5196b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                mDescriptionFadeOutAnimator.start();
520d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            }
521d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        } else {
522d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (fadeIn) {
523d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mBgFadeOutAnimator.reverse();
524d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mControlRowFadeOutAnimator.reverse();
525d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mOtherRowFadeOutAnimator.reverse();
5266b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                mDescriptionFadeOutAnimator.reverse();
527d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            } else {
528d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mBgFadeInAnimator.reverse();
529d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mControlRowFadeInAnimator.reverse();
530d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                mOtherRowFadeInAnimator.reverse();
5316b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                mDescriptionFadeInAnimator.reverse();
532d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            }
533d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        }
534d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
535d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        // If fading in while control row is focused, set initial translationY so
536d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        // views slide in from below.
5376b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        if (fadeIn && mFadingStatus == IDLE) {
538d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            final int count = getVerticalGridView().getChildCount();
539d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            for (int i = 0; i < count; i++) {
5406b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                getVerticalGridView().getChildAt(i).setTranslationY(mAnimationTranslateY);
541d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            }
542d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        }
543d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
544372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        mFadingStatus = fadeIn ? IN : OUT;
545372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout    }
5467ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout
5477ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    /**
5487ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout     * Sets the list of rows for the fragment.
5497ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout     */
5507ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    @Override
5517ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    public void setAdapter(ObjectAdapter adapter) {
5526dca725412977bb56b933bdec120e31909233cdbCraig Stout        if (getAdapter() != null) {
5536dca725412977bb56b933bdec120e31909233cdbCraig Stout            getAdapter().unregisterObserver(mObserver);
5546dca725412977bb56b933bdec120e31909233cdbCraig Stout        }
5557ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        super.setAdapter(adapter);
5566dca725412977bb56b933bdec120e31909233cdbCraig Stout        if (adapter != null) {
5576dca725412977bb56b933bdec120e31909233cdbCraig Stout            adapter.registerObserver(mObserver);
5586dca725412977bb56b933bdec120e31909233cdbCraig Stout        }
5597ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    }
5607ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout
5617ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    @Override
5627ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    void setVerticalGridViewLayout(VerticalGridView listview) {
563d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        if (listview == null) {
5647ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout            return;
5657ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        }
566d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        // Padding affects alignment when last row is focused
567d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        // (last is first when there's only one row).
568d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        setBottomPadding(listview, mPaddingBottom);
569d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout
570d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        // Item alignment affects focused row that isn't the last.
571d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        listview.setItemAlignmentOffset(mAlignPosition);
5727ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        listview.setItemAlignmentOffsetPercent(100);
573d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout
574d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        // Push rows to the bottom.
5757ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        listview.setWindowAlignmentOffset(0);
5767ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        listview.setWindowAlignmentOffsetPercent(100);
5777ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE);
5787ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    }
5797ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout
580d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout    private static void setBottomPadding(View view, int padding) {
581d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        view.setPadding(view.getPaddingLeft(), view.getPaddingTop(),
582d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout                view.getPaddingRight(), padding);
583d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout    }
584d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout
5857ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    @Override
5867ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    public void onCreate(Bundle savedInstanceState) {
5877ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        super.onCreate(savedInstanceState);
5887ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout
5897ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout        mAlignPosition =
590d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_align_bottom);
591d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        mPaddingBottom =
592d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom);
5937709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        mBgDarkColor =
5947709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout                getResources().getColor(R.color.lb_playback_controls_background_dark);
5957709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        mBgLightColor =
5967709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout                getResources().getColor(R.color.lb_playback_controls_background_light);
597372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        mShowTimeMs =
598372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                getResources().getInteger(R.integer.lb_playback_controls_show_time_ms);
5996b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mMajorFadeTranslateY =
6006b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                getResources().getDimensionPixelSize(R.dimen.lb_playback_major_fade_translate_y);
6016b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        mMinorFadeTranslateY =
6026b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout                getResources().getDimensionPixelSize(R.dimen.lb_playback_minor_fade_translate_y);
603d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
604d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        loadBgAnimator();
605d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        loadControlRowAnimator();
606d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        loadOtherRowAnimator();
6076b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout        loadDescriptionAnimator();
6087709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    }
6097709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout
6107709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    /**
6117709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     * Sets the background type.
6127709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     *
6137709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     * @param type One of BG_LIGHT, BG_DARK, or BG_NONE.
6147709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     */
6157709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    public void setBackgroundType(int type) {
616372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        switch (type) {
617372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        case BG_LIGHT:
618372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        case BG_DARK:
619372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        case BG_NONE:
620372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            if (type != mBackgroundType) {
621372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                mBackgroundType = type;
622372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout                updateBackground();
623372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            }
624372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout            break;
625372d07bb41510d91a6a662a1906aceb0ee759481Craig Stout        default:
6267709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout            throw new IllegalArgumentException("Invalid background type");
6277709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        }
6287709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    }
6297709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout
6307709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    /**
6317709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     * Returns the background type.
6327709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout     */
6337709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    public int getBackgroundType() {
6347709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        return mBackgroundType;
6357709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    }
6367709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout
6377709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    private void updateBackground() {
6387709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        if (mRootView != null) {
6397709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout            int color = mBgDarkColor;
6407709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout            switch (mBackgroundType) {
6417709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout                case BG_DARK: break;
6427709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout                case BG_LIGHT: color = mBgLightColor; break;
6437709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout                case BG_NONE: color = Color.TRANSPARENT; break;
6447709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout            }
6457709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout            mRootView.setBackground(new ColorDrawable(color));
6467709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        }
6477709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    }
6487709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout
649d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout    private void updateControlsBottomSpace(ItemBridgeAdapter.ViewHolder vh) {
650d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        // Add extra space between rows 0 and 1
651d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        if (vh == null && getVerticalGridView() != null) {
652d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout            vh = (ItemBridgeAdapter.ViewHolder)
653d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout                    getVerticalGridView().findViewHolderForPosition(0);
654d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        }
655d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        if (vh != null && vh.getPresenter() instanceof PlaybackControlsRowPresenter) {
656d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout            final int adapterSize = getAdapter() == null ? 0 : getAdapter().size();
657d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout            ((PlaybackControlsRowPresenter) vh.getPresenter()).showBottomSpace(
658d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout                    (PlaybackControlsRowPresenter.ViewHolder) vh.getViewHolder(),
659d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout                    adapterSize > 1);
660d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        }
661d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout    }
662d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout
663d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    private final ItemBridgeAdapter.AdapterListener mAdapterListener =
664d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            new ItemBridgeAdapter.AdapterListener() {
665d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        @Override
666d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder vh) {
667d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (DEBUG) Log.v(TAG, "onAttachedToWindow " + vh.getViewHolder().view);
668d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if ((mFadingStatus == IDLE && mBgAlpha == 0) || mFadingStatus == OUT) {
669d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                if (DEBUG) Log.v(TAG, "setting alpha to 0");
670d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout                vh.getViewHolder().view.setAlpha(0);
671d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            }
672aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout            if (vh.getPosition() == 0 && mResetControlsToPrimaryActionsPending) {
673aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout                resetControlsToPrimaryActions(vh);
674aa67105babce5fb14e1f39b57d4c84ce634afa62Craig Stout            }
675d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        }
676d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        @Override
677d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder vh) {
678d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            if (DEBUG) Log.v(TAG, "onDetachedFromWindow " + vh.getViewHolder().view);
679d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            // Reset animation state
680d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            vh.getViewHolder().view.setAlpha(1f);
681d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout            vh.getViewHolder().view.setTranslationY(0);
6826b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout            if (vh.getViewHolder() instanceof PlaybackControlsRowPresenter.ViewHolder) {
6838f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                Presenter.ViewHolder descriptionVh = ((PlaybackControlsRowPresenter.ViewHolder)
6848f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                        vh.getViewHolder()).mDescriptionViewHolder;
6858f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                if (descriptionVh != null) {
6868f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                    descriptionVh.view.setAlpha(1f);
6878f5c183ba7b9df6b5339586f51219b4d5e6305f3Craig Stout                }
6886b2e5b5117f1b8dfafbd81b995bb423ab0297564Craig Stout            }
689d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        }
690d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        @Override
691d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        public void onBind(ItemBridgeAdapter.ViewHolder vh) {
692d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout            if (vh.getPosition() == 0) {
693d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout                updateControlsBottomSpace(vh);
694d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout            }
695d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout        }
696d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout    };
697d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout
6987709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    @Override
6997709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout    public View onCreateView(LayoutInflater inflater, ViewGroup container,
7007709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout            Bundle savedInstanceState) {
7017709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        mRootView = super.onCreateView(inflater, container, savedInstanceState);
702d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        mBgAlpha = 255;
7037709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        updateBackground();
704d1adbdcb44a48e142d28a93189c57edfe62d93ceCraig Stout        getRowsFragment().setExternalAdapterListener(mAdapterListener);
7057709709c2c78490a21311e9950d5dca7e89a6aedCraig Stout        return mRootView;
7067ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout    }
7076dca725412977bb56b933bdec120e31909233cdbCraig Stout
7081e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout    @Override
7091e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout    public void onDestroyView() {
7101e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout        mRootView = null;
7111e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout        super.onDestroyView();
7121e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout    }
7131e5725d52c7ec12b184dcfce6bfafa80aed35230Craig Stout
7146dca725412977bb56b933bdec120e31909233cdbCraig Stout    private final DataObserver mObserver = new DataObserver() {
7156dca725412977bb56b933bdec120e31909233cdbCraig Stout        public void onChanged() {
716d20507e0f5ac7ad021f42ca87c294787246f0591Craig Stout            updateControlsBottomSpace(null);
7176dca725412977bb56b933bdec120e31909233cdbCraig Stout        }
7186dca725412977bb56b933bdec120e31909233cdbCraig Stout    };
7192d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout
7202d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout    static abstract class AnimatorListener implements Animator.AnimatorListener {
7212d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        ArrayList<View> mViews = new ArrayList<View>();
7222d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        ArrayList<Integer> mLayerType = new ArrayList<Integer>();
7232d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout
7242d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        public void onAnimationCancel(Animator animation) {
7252d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        }
7262d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        public void onAnimationRepeat(Animator animation) {
7272d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        }
7282d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        public void onAnimationStart(Animator animation) {
7292d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            getViews(mViews);
7302d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            for (View view : mViews) {
7312d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                mLayerType.add(view.getLayerType());
7322d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
7332d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            }
7342d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        }
7352d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        public void onAnimationEnd(Animator animation) {
7362d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            for (int i = 0; i < mViews.size(); i++) {
7372d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout                mViews.get(i).setLayerType(mLayerType.get(i), null);
7382d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            }
7392d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            mLayerType.clear();
7402d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout            mViews.clear();
7412d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        }
7422d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout        abstract void getViews(ArrayList<View> views);
7432d33e3cfedc56adc2d4e5ac6279ec683d041fe21Craig Stout    };
7447ab1edf2b49f3cdcb9db7a1c60d0dc1e17a9aef7Craig Stout}
745