147520b68e50572a9775a662410c5aff8300c8784Craig Stout/*
247520b68e50572a9775a662410c5aff8300c8784Craig Stout * Copyright (C) 2014 The Android Open Source Project
347520b68e50572a9775a662410c5aff8300c8784Craig Stout *
447520b68e50572a9775a662410c5aff8300c8784Craig Stout * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
547520b68e50572a9775a662410c5aff8300c8784Craig Stout * in compliance with the License. You may obtain a copy of the License at
647520b68e50572a9775a662410c5aff8300c8784Craig Stout *
747520b68e50572a9775a662410c5aff8300c8784Craig Stout * http://www.apache.org/licenses/LICENSE-2.0
847520b68e50572a9775a662410c5aff8300c8784Craig Stout *
947520b68e50572a9775a662410c5aff8300c8784Craig Stout * Unless required by applicable law or agreed to in writing, software distributed under the License
1047520b68e50572a9775a662410c5aff8300c8784Craig Stout * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
1147520b68e50572a9775a662410c5aff8300c8784Craig Stout * or implied. See the License for the specific language governing permissions and limitations under
1247520b68e50572a9775a662410c5aff8300c8784Craig Stout * the License.
1347520b68e50572a9775a662410c5aff8300c8784Craig Stout */
1447520b68e50572a9775a662410c5aff8300c8784Craig Stoutpackage android.support.v17.leanback.widget;
1547520b68e50572a9775a662410c5aff8300c8784Craig Stout
16892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.content.Context;
179240e796bc63422c28f2707840bd99c48573279bDake Guimport android.content.res.TypedArray;
18892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.support.v17.leanback.R;
19cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Guimport android.support.v17.leanback.graphics.ColorOverlayDimmer;
20c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Guimport android.support.v17.leanback.widget.RowPresenter.ViewHolder;
214cd4cce277571385f4d1a56d5348578c38368cbeCraig Stoutimport android.util.Log;
2247520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.View;
2347520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.ViewGroup;
24892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.view.ViewGroup.LayoutParams;
2547520b68e50572a9775a662410c5aff8300c8784Craig Stout
26bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stoutimport java.util.HashMap;
27bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout
2847520b68e50572a9775a662410c5aff8300c8784Craig Stout/**
297aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * ListRowPresenter renders {@link ListRow} using a
30cb13a318e577e14461eb008071dddf762847de42Dake Gu * {@link HorizontalGridView} hosted in a {@link ListRowView}.
317aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu *
327aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * <h3>Hover card</h3>
3347520b68e50572a9775a662410c5aff8300c8784Craig Stout * Optionally, {@link #setHoverCardPresenterSelector(PresenterSelector)} can be used to
3447520b68e50572a9775a662410c5aff8300c8784Craig Stout * display a view for the currently focused list item below the rendered
3547520b68e50572a9775a662410c5aff8300c8784Craig Stout * list. This view is known as a hover card.
367aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu *
377aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * <h3>Selection animation</h3>
387aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * ListRowPresenter disables {@link RowPresenter}'s default dimming effect and draw
397aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * a dim overlay on top of each individual child items.  Subclass may override and disable
407aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * {@link #isUsingDefaultListSelectEffect()} and write its own dim effect in
417aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * {@link #onSelectLevelChanged(RowPresenter.ViewHolder)}.
42dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu *
43dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * <h3>Shadow</h3>
44dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * ListRowPresenter applies a default shadow to child of each view.  Call
45dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * {@link #setShadowEnabled(boolean)} to disable shadow.  Subclass may override and return
46dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * false in {@link #isUsingDefaultShadow()} and replace with its own shadow implementation.
4747520b68e50572a9775a662410c5aff8300c8784Craig Stout */
4847520b68e50572a9775a662410c5aff8300c8784Craig Stoutpublic class ListRowPresenter extends RowPresenter {
4947520b68e50572a9775a662410c5aff8300c8784Craig Stout
5047520b68e50572a9775a662410c5aff8300c8784Craig Stout    private static final String TAG = "ListRowPresenter";
5147520b68e50572a9775a662410c5aff8300c8784Craig Stout    private static final boolean DEBUG = false;
5247520b68e50572a9775a662410c5aff8300c8784Craig Stout
53bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    private static final int DEFAULT_RECYCLED_POOL_SIZE = 24;
54bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout
5547520b68e50572a9775a662410c5aff8300c8784Craig Stout    public static class ViewHolder extends RowPresenter.ViewHolder {
5647520b68e50572a9775a662410c5aff8300c8784Craig Stout        final ListRowPresenter mListRowPresenter;
5747520b68e50572a9775a662410c5aff8300c8784Craig Stout        final HorizontalGridView mGridView;
5847520b68e50572a9775a662410c5aff8300c8784Craig Stout        final ItemBridgeAdapter mItemBridgeAdapter = new ItemBridgeAdapter();
5947520b68e50572a9775a662410c5aff8300c8784Craig Stout        final HorizontalHoverCardSwitcher mHoverCardViewSwitcher = new HorizontalHoverCardSwitcher();
60e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu        final int mPaddingTop;
61e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu        final int mPaddingBottom;
62e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu        final int mPaddingLeft;
63e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu        final int mPaddingRight;
6447520b68e50572a9775a662410c5aff8300c8784Craig Stout
6547520b68e50572a9775a662410c5aff8300c8784Craig Stout        public ViewHolder(View rootView, HorizontalGridView gridView, ListRowPresenter p) {
6647520b68e50572a9775a662410c5aff8300c8784Craig Stout            super(rootView);
6747520b68e50572a9775a662410c5aff8300c8784Craig Stout            mGridView = gridView;
6847520b68e50572a9775a662410c5aff8300c8784Craig Stout            mListRowPresenter = p;
69e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu            mPaddingTop = mGridView.getPaddingTop();
70e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu            mPaddingBottom = mGridView.getPaddingBottom();
71e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu            mPaddingLeft = mGridView.getPaddingLeft();
72e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu            mPaddingRight = mGridView.getPaddingRight();
7347520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
7447520b68e50572a9775a662410c5aff8300c8784Craig Stout
7547520b68e50572a9775a662410c5aff8300c8784Craig Stout        public final ListRowPresenter getListRowPresenter() {
7647520b68e50572a9775a662410c5aff8300c8784Craig Stout            return mListRowPresenter;
7747520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
7847520b68e50572a9775a662410c5aff8300c8784Craig Stout
7947520b68e50572a9775a662410c5aff8300c8784Craig Stout        public final HorizontalGridView getGridView() {
8047520b68e50572a9775a662410c5aff8300c8784Craig Stout            return mGridView;
8147520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
829de682083d3da5b1127969ee1fd7b74561aa9acdCraig Stout
839de682083d3da5b1127969ee1fd7b74561aa9acdCraig Stout        public final ItemBridgeAdapter getBridgeAdapter() {
849de682083d3da5b1127969ee1fd7b74561aa9acdCraig Stout            return mItemBridgeAdapter;
859de682083d3da5b1127969ee1fd7b74561aa9acdCraig Stout        }
8647520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
8747520b68e50572a9775a662410c5aff8300c8784Craig Stout
88a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    private int mRowHeight;
89a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    private int mExpandedRowHeight;
9047520b68e50572a9775a662410c5aff8300c8784Craig Stout    private PresenterSelector mHoverCardPresenterSelector;
91b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    private int mZoomFactor;
92892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    private boolean mShadowEnabled = true;
939240e796bc63422c28f2707840bd99c48573279bDake Gu    private int mBrowseRowsFadingEdgeLength = -1;
944f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout    private boolean mRoundedCornersEnabled = true;
95bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    private HashMap<Presenter, Integer> mRecycledPoolSize = new HashMap<Presenter, Integer>();
96b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout
974cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    private static int sSelectedRowTopPadding;
984cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    private static int sExpandedSelectedRowTopPadding;
994cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    private static int sExpandedRowNoHovercardBottomPadding;
1004cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout
101b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    /**
102b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     * Constructs a ListRowPresenter with defaults.
103739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Uses {@link FocusHighlight#ZOOM_FACTOR_MEDIUM} for focus zooming.
104b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     */
105b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    public ListRowPresenter() {
106739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        this(FocusHighlight.ZOOM_FACTOR_MEDIUM);
107b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    }
108b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout
109b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    /**
110b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     * Constructs a ListRowPresenter with the given parameters.
111b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     *
112b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     * @param zoomFactor Controls the zoom factor used when an item view is focused. One of
113739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_NONE},
114739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_SMALL},
115739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_MEDIUM},
116739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_LARGE}
117b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     */
118b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    public ListRowPresenter(int zoomFactor) {
119b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout        mZoomFactor = zoomFactor;
120b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    }
121b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout
122b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    /**
123f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * Sets the row height for rows created by this Presenter. Rows
124a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     * created before calling this method will not be updated.
125a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     *
126f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * @param rowHeight Row height in pixels, or WRAP_CONTENT, or 0
127f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * to use the default height.
128a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     */
129a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    public void setRowHeight(int rowHeight) {
130a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        mRowHeight = rowHeight;
131a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    }
132a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn
133a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    /**
134f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * Returns the row height for list rows created by this Presenter.
135a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     */
136a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    public int getRowHeight() {
137a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        return mRowHeight;
138a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    }
139a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn
140a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    /**
141f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * Sets the expanded row height for rows created by this Presenter.
142f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * If not set, expanded rows have the same height as unexpanded
143a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     * rows.
144a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     *
145f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * @param rowHeight The row height in to use when the row is expanded,
146f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     *        in pixels, or WRAP_CONTENT, or 0 to use the default.
147a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     */
148a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    public void setExpandedRowHeight(int rowHeight) {
149a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        mExpandedRowHeight = rowHeight;
150a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    }
151a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn
152a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    /**
153f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * Returns the expanded row height for rows created by this Presenter.
154a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     */
155a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    public int getExpandedRowHeight() {
156f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout        return mExpandedRowHeight != 0 ? mExpandedRowHeight : mRowHeight;
157a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    }
158a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn
159a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    /**
160b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     * Returns the zoom factor used for focus highlighting.
161b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     */
162b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    public final int getZoomFactor() {
163b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout        return mZoomFactor;
164b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    }
16547520b68e50572a9775a662410c5aff8300c8784Craig Stout
166892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    private ItemBridgeAdapter.Wrapper mCardWrapper = new ItemBridgeAdapter.Wrapper() {
167892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        @Override
168892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        public View createWrapper(View root) {
169dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu            ShadowOverlayContainer wrapper = new ShadowOverlayContainer(root.getContext());
170892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            wrapper.setLayoutParams(
171892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                    new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
1724f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout            wrapper.initialize(needsDefaultShadow(),
1734f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout                    needsDefaultListSelectEffect(),
1744f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout                    areChildRoundedCornersEnabled());
175892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            return wrapper;
176892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        }
177892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        @Override
178892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        public void wrap(View wrapper, View wrapped) {
179dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu            ((ShadowOverlayContainer) wrapper).wrap(wrapped);
180892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        }
181892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    };
182892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
18347520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
18447520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected void initializeRowViewHolder(RowPresenter.ViewHolder holder) {
18547520b68e50572a9775a662410c5aff8300c8784Craig Stout        super.initializeRowViewHolder(holder);
18647520b68e50572a9775a662410c5aff8300c8784Craig Stout        final ViewHolder rowViewHolder = (ViewHolder) holder;
1874f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout        if (needsDefaultListSelectEffect() || needsDefaultShadow()
1884f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout                || areChildRoundedCornersEnabled()) {
189892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            rowViewHolder.mItemBridgeAdapter.setWrapper(mCardWrapper);
190892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        }
191cb13a318e577e14461eb008071dddf762847de42Dake Gu        if (needsDefaultListSelectEffect()) {
192dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu            ShadowOverlayContainer.prepareParentForShadow(rowViewHolder.mGridView);
193cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        }
19446e7de54775fc37dc51041629c79249e6dae3242Dake Gu        FocusHighlightHelper.setupBrowseItemFocusHighlight(rowViewHolder.mItemBridgeAdapter,
19546e7de54775fc37dc51041629c79249e6dae3242Dake Gu                mZoomFactor, false);
1960fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu        rowViewHolder.mGridView.setFocusDrawingOrderEnabled(!isUsingZOrder());
19747520b68e50572a9775a662410c5aff8300c8784Craig Stout        rowViewHolder.mGridView.setOnChildSelectedListener(
19847520b68e50572a9775a662410c5aff8300c8784Craig Stout                new OnChildSelectedListener() {
19947520b68e50572a9775a662410c5aff8300c8784Craig Stout            @Override
20047520b68e50572a9775a662410c5aff8300c8784Craig Stout            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
20147520b68e50572a9775a662410c5aff8300c8784Craig Stout                selectChildView(rowViewHolder, view);
20247520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
20347520b68e50572a9775a662410c5aff8300c8784Craig Stout        });
204892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        rowViewHolder.mItemBridgeAdapter.setAdapterListener(
205892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                new ItemBridgeAdapter.AdapterListener() {
206892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            @Override
20753a46b5723708bbb223084ebf3a4fbf6ea4616aeDake Gu            public void onBind(final ItemBridgeAdapter.ViewHolder viewHolder) {
208892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                // Only when having an OnItemClickListner, we will attach the OnClickListener.
2099de363b8db05106b03d115c266859fe200d41db7Dake Gu                if (getOnItemClickedListener() != null || getOnItemViewClickedListener() != null) {
21047520b68e50572a9775a662410c5aff8300c8784Craig Stout                    viewHolder.mHolder.view.setOnClickListener(new View.OnClickListener() {
21147520b68e50572a9775a662410c5aff8300c8784Craig Stout                        @Override
21247520b68e50572a9775a662410c5aff8300c8784Craig Stout                        public void onClick(View v) {
21347520b68e50572a9775a662410c5aff8300c8784Craig Stout                            ItemBridgeAdapter.ViewHolder ibh = (ItemBridgeAdapter.ViewHolder)
2149de363b8db05106b03d115c266859fe200d41db7Dake Gu                                    rowViewHolder.mGridView
2159de363b8db05106b03d115c266859fe200d41db7Dake Gu                                            .getChildViewHolder(viewHolder.itemView);
21647520b68e50572a9775a662410c5aff8300c8784Craig Stout                            if (getOnItemClickedListener() != null) {
21747520b68e50572a9775a662410c5aff8300c8784Craig Stout                                getOnItemClickedListener().onItemClicked(ibh.mItem,
21847520b68e50572a9775a662410c5aff8300c8784Craig Stout                                        (ListRow) rowViewHolder.mRow);
21947520b68e50572a9775a662410c5aff8300c8784Craig Stout                            }
2209de363b8db05106b03d115c266859fe200d41db7Dake Gu                            if (getOnItemViewClickedListener() != null) {
2219de363b8db05106b03d115c266859fe200d41db7Dake Gu                                getOnItemViewClickedListener().onItemClicked(viewHolder.mHolder,
2229de363b8db05106b03d115c266859fe200d41db7Dake Gu                                        ibh.mItem, rowViewHolder, (ListRow) rowViewHolder.mRow);
2239de363b8db05106b03d115c266859fe200d41db7Dake Gu                            }
22447520b68e50572a9775a662410c5aff8300c8784Craig Stout                        }
22547520b68e50572a9775a662410c5aff8300c8784Craig Stout                    });
22647520b68e50572a9775a662410c5aff8300c8784Craig Stout                }
227892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            }
228892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
229892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            @Override
23053a46b5723708bbb223084ebf3a4fbf6ea4616aeDake Gu            public void onUnbind(ItemBridgeAdapter.ViewHolder viewHolder) {
23153a46b5723708bbb223084ebf3a4fbf6ea4616aeDake Gu                if (getOnItemClickedListener() != null || getOnItemViewClickedListener() != null) {
23253a46b5723708bbb223084ebf3a4fbf6ea4616aeDake Gu                    viewHolder.mHolder.view.setOnClickListener(null);
23353a46b5723708bbb223084ebf3a4fbf6ea4616aeDake Gu                }
23453a46b5723708bbb223084ebf3a4fbf6ea4616aeDake Gu            }
23553a46b5723708bbb223084ebf3a4fbf6ea4616aeDake Gu
23653a46b5723708bbb223084ebf3a4fbf6ea4616aeDake Gu            @Override
23729246e5ca814f17dcf368eeacd1b44a329592ae0Dake Gu            public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) {
238dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu                if (viewHolder.itemView instanceof ShadowOverlayContainer) {
239892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                    int dimmedColor = rowViewHolder.mColorDimmer.getPaint().getColor();
240dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu                    ((ShadowOverlayContainer) viewHolder.itemView).setOverlayColor(dimmedColor);
241892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                }
2424df06cbe8f6dd087fc8f1068faa77923cb297365Tim Kilbourn                viewHolder.itemView.setActivated(rowViewHolder.mExpanded);
243892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            }
2449de682083d3da5b1127969ee1fd7b74561aa9acdCraig Stout
2459de682083d3da5b1127969ee1fd7b74561aa9acdCraig Stout            @Override
2469de682083d3da5b1127969ee1fd7b74561aa9acdCraig Stout            public void onAddPresenter(Presenter presenter, int type) {
247bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout                rowViewHolder.getGridView().getRecycledViewPool().setMaxRecycledViews(
248bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout                        type, getRecycledPoolSize(presenter));
2499de682083d3da5b1127969ee1fd7b74561aa9acdCraig Stout            }
250892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        });
25147520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
25247520b68e50572a9775a662410c5aff8300c8784Craig Stout
253cb13a318e577e14461eb008071dddf762847de42Dake Gu    final boolean needsDefaultListSelectEffect() {
254cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        return isUsingDefaultListSelectEffect() && getSelectEffectEnabled();
255cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
256cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
25747520b68e50572a9775a662410c5aff8300c8784Craig Stout    /**
258bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout     * Sets the recycled pool size for the given presenter.
259bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout     */
260bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    public void setRecycledPoolSize(Presenter presenter, int size) {
261bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout        mRecycledPoolSize.put(presenter, size);
262bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    }
263bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout
264bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    /**
265bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout     * Returns the recycled pool size for the given presenter.
266bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout     */
267bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    public int getRecycledPoolSize(Presenter presenter) {
268bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout        return mRecycledPoolSize.containsKey(presenter) ? mRecycledPoolSize.get(presenter) :
269bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout                DEFAULT_RECYCLED_POOL_SIZE;
270bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    }
271bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout
272bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    /**
27347520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Set {@link PresenterSelector} used for showing a select object in a hover card.
27447520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
27547520b68e50572a9775a662410c5aff8300c8784Craig Stout    public final void setHoverCardPresenterSelector(PresenterSelector selector) {
27647520b68e50572a9775a662410c5aff8300c8784Craig Stout        mHoverCardPresenterSelector = selector;
27747520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
27847520b68e50572a9775a662410c5aff8300c8784Craig Stout
27947520b68e50572a9775a662410c5aff8300c8784Craig Stout    /**
28047520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Get {@link PresenterSelector} used for showing a select object in a hover card.
28147520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
28247520b68e50572a9775a662410c5aff8300c8784Craig Stout    public final PresenterSelector getHoverCardPresenterSelector() {
28347520b68e50572a9775a662410c5aff8300c8784Craig Stout        return mHoverCardPresenterSelector;
28447520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
28547520b68e50572a9775a662410c5aff8300c8784Craig Stout
28647520b68e50572a9775a662410c5aff8300c8784Craig Stout    /*
28747520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Perform operations when a child of horizontal grid view is selected.
28847520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
28947520b68e50572a9775a662410c5aff8300c8784Craig Stout    private void selectChildView(ViewHolder rowViewHolder, View view) {
29047520b68e50572a9775a662410c5aff8300c8784Craig Stout        ItemBridgeAdapter.ViewHolder ibh = null;
29147520b68e50572a9775a662410c5aff8300c8784Craig Stout        if (view != null) {
29247520b68e50572a9775a662410c5aff8300c8784Craig Stout            ibh = (ItemBridgeAdapter.ViewHolder)
29347520b68e50572a9775a662410c5aff8300c8784Craig Stout                    rowViewHolder.mGridView.getChildViewHolder(view);
29447520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
29547520b68e50572a9775a662410c5aff8300c8784Craig Stout        if (view == null) {
29647520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (mHoverCardPresenterSelector != null) {
29747520b68e50572a9775a662410c5aff8300c8784Craig Stout                rowViewHolder.mHoverCardViewSwitcher.unselect();
29847520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
2999de363b8db05106b03d115c266859fe200d41db7Dake Gu            if (getOnItemViewSelectedListener() != null) {
3009de363b8db05106b03d115c266859fe200d41db7Dake Gu                getOnItemViewSelectedListener().onItemSelected(null, null,
3019de363b8db05106b03d115c266859fe200d41db7Dake Gu                        rowViewHolder, rowViewHolder.mRow);
3029de363b8db05106b03d115c266859fe200d41db7Dake Gu            }
30347520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (getOnItemSelectedListener() != null) {
30447520b68e50572a9775a662410c5aff8300c8784Craig Stout                getOnItemSelectedListener().onItemSelected(null, rowViewHolder.mRow);
30547520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
30647520b68e50572a9775a662410c5aff8300c8784Craig Stout        } else if (rowViewHolder.mExpanded && rowViewHolder.mSelected) {
30747520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (mHoverCardPresenterSelector != null) {
30847520b68e50572a9775a662410c5aff8300c8784Craig Stout                rowViewHolder.mHoverCardViewSwitcher.select(rowViewHolder.mGridView, view,
30947520b68e50572a9775a662410c5aff8300c8784Craig Stout                        ibh.mItem);
31047520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
3119de363b8db05106b03d115c266859fe200d41db7Dake Gu            if (getOnItemViewSelectedListener() != null) {
3129de363b8db05106b03d115c266859fe200d41db7Dake Gu                getOnItemViewSelectedListener().onItemSelected(ibh.mHolder, ibh.mItem,
3139de363b8db05106b03d115c266859fe200d41db7Dake Gu                        rowViewHolder, rowViewHolder.mRow);
3149de363b8db05106b03d115c266859fe200d41db7Dake Gu            }
31547520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (getOnItemSelectedListener() != null) {
31647520b68e50572a9775a662410c5aff8300c8784Craig Stout                getOnItemSelectedListener().onItemSelected(ibh.mItem, rowViewHolder.mRow);
31747520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
31847520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
31947520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
32047520b68e50572a9775a662410c5aff8300c8784Craig Stout
3214cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    private static void initStatics(Context context) {
3224cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        if (sSelectedRowTopPadding == 0) {
3234cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            sSelectedRowTopPadding = context.getResources().getDimensionPixelSize(
3244cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout                    R.dimen.lb_browse_selected_row_top_padding);
3254cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            sExpandedSelectedRowTopPadding = context.getResources().getDimensionPixelSize(
3264cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout                    R.dimen.lb_browse_expanded_selected_row_top_padding);
3274cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            sExpandedRowNoHovercardBottomPadding = context.getResources().getDimensionPixelSize(
3284cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout                    R.dimen.lb_browse_expanded_row_no_hovercard_bottom_padding);
3294cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        }
3304cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    }
3314cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout
3324cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    private int getSpaceUnderBaseline(ListRowPresenter.ViewHolder vh) {
3334cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        RowHeaderPresenter.ViewHolder headerViewHolder = vh.getHeaderViewHolder();
3344cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        if (headerViewHolder != null) {
3354cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            if (getHeaderPresenter() != null) {
3364cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout                return getHeaderPresenter().getSpaceUnderBaseline(headerViewHolder);
3374cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            }
3384cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            return headerViewHolder.view.getPaddingBottom();
3394cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        }
3404cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        return 0;
3414cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    }
3424cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout
3434cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    private void setVerticalPadding(ListRowPresenter.ViewHolder vh) {
3444cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        int paddingTop, paddingBottom;
3453146269a82645438b55a41c679047e3be36e65dfCraig Stout        // Note: sufficient bottom padding needed for card shadows.
3464cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        if (vh.isExpanded()) {
3474cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            int headerSpaceUnderBaseline = getSpaceUnderBaseline(vh);
3484cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            if (DEBUG) Log.v(TAG, "headerSpaceUnderBaseline " + headerSpaceUnderBaseline);
3494cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            paddingTop = (vh.isSelected() ? sExpandedSelectedRowTopPadding : vh.mPaddingTop) -
3504cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout                    headerSpaceUnderBaseline;
3514cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            paddingBottom = mHoverCardPresenterSelector == null ?
3524cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout                    sExpandedRowNoHovercardBottomPadding : vh.mPaddingBottom;
3534cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        } else if (vh.isSelected()) {
3543146269a82645438b55a41c679047e3be36e65dfCraig Stout            paddingTop = sSelectedRowTopPadding - vh.mPaddingBottom;
3553146269a82645438b55a41c679047e3be36e65dfCraig Stout            paddingBottom = sSelectedRowTopPadding;
3564cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        } else {
3573146269a82645438b55a41c679047e3be36e65dfCraig Stout            paddingTop = 0;
3583146269a82645438b55a41c679047e3be36e65dfCraig Stout            paddingBottom = vh.mPaddingBottom;
3594cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        }
3604cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        vh.getGridView().setPadding(vh.mPaddingLeft, paddingTop, vh.mPaddingRight,
3614cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout                paddingBottom);
3624cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    }
3634cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout
36447520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
36547520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) {
3664cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        initStatics(parent.getContext());
367cb13a318e577e14461eb008071dddf762847de42Dake Gu        ListRowView rowView = new ListRowView(parent.getContext());
3689240e796bc63422c28f2707840bd99c48573279bDake Gu        setupFadingEffect(rowView);
369f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout        if (mRowHeight != 0) {
370a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn            rowView.getGridView().setRowHeight(mRowHeight);
371a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        }
37247520b68e50572a9775a662410c5aff8300c8784Craig Stout        return new ViewHolder(rowView, rowView.getGridView(), this);
37347520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
37447520b68e50572a9775a662410c5aff8300c8784Craig Stout
37547520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
37647520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected void onRowViewSelected(RowPresenter.ViewHolder holder, boolean selected) {
3772f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        super.onRowViewSelected(holder, selected);
3784cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        ViewHolder vh = (ViewHolder) holder;
3794cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        setVerticalPadding(vh);
3804cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        updateFooterViewSwitcher(vh);
38147520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
38247520b68e50572a9775a662410c5aff8300c8784Craig Stout
38347520b68e50572a9775a662410c5aff8300c8784Craig Stout    /*
38447520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Show or hide hover card when row selection or expanded state is changed.
38547520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
38647520b68e50572a9775a662410c5aff8300c8784Craig Stout    private void updateFooterViewSwitcher(ViewHolder vh) {
38747520b68e50572a9775a662410c5aff8300c8784Craig Stout        if (vh.mExpanded && vh.mSelected) {
38847520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (mHoverCardPresenterSelector != null) {
38947520b68e50572a9775a662410c5aff8300c8784Craig Stout                vh.mHoverCardViewSwitcher.init((ViewGroup) vh.view,
39047520b68e50572a9775a662410c5aff8300c8784Craig Stout                        mHoverCardPresenterSelector);
39147520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
39202e411c2c69d20aab138f1a162a24ea650eff7a1Dake Gu            ItemBridgeAdapter.ViewHolder ibh = (ItemBridgeAdapter.ViewHolder)
39302e411c2c69d20aab138f1a162a24ea650eff7a1Dake Gu                    vh.mGridView.findViewHolderForPosition(
39402e411c2c69d20aab138f1a162a24ea650eff7a1Dake Gu                            vh.mGridView.getSelectedPosition());
39502e411c2c69d20aab138f1a162a24ea650eff7a1Dake Gu            selectChildView(vh, ibh == null ? null : ibh.itemView);
39647520b68e50572a9775a662410c5aff8300c8784Craig Stout        } else {
39747520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (mHoverCardPresenterSelector != null) {
3982f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu                vh.mHoverCardViewSwitcher.unselect();
39947520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
40047520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
40147520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
40247520b68e50572a9775a662410c5aff8300c8784Craig Stout
4039240e796bc63422c28f2707840bd99c48573279bDake Gu    private void setupFadingEffect(ListRowView rowView) {
4049240e796bc63422c28f2707840bd99c48573279bDake Gu        // content is completely faded at 1/2 padding of left, fading length is 1/2 of padding.
4059240e796bc63422c28f2707840bd99c48573279bDake Gu        HorizontalGridView gridView = rowView.getGridView();
4069240e796bc63422c28f2707840bd99c48573279bDake Gu        if (mBrowseRowsFadingEdgeLength < 0) {
4079240e796bc63422c28f2707840bd99c48573279bDake Gu            TypedArray ta = gridView.getContext()
4089240e796bc63422c28f2707840bd99c48573279bDake Gu                    .obtainStyledAttributes(R.styleable.LeanbackTheme);
4099240e796bc63422c28f2707840bd99c48573279bDake Gu            mBrowseRowsFadingEdgeLength = (int) ta.getDimension(
4109240e796bc63422c28f2707840bd99c48573279bDake Gu                    R.styleable.LeanbackTheme_browseRowsFadingEdgeLength, 0);
4119240e796bc63422c28f2707840bd99c48573279bDake Gu            ta.recycle();
41247520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
4139240e796bc63422c28f2707840bd99c48573279bDake Gu        gridView.setFadingLeftEdgeLength(mBrowseRowsFadingEdgeLength);
41447520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
41547520b68e50572a9775a662410c5aff8300c8784Craig Stout
41647520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
41747520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected void onRowViewExpanded(RowPresenter.ViewHolder holder, boolean expanded) {
41847520b68e50572a9775a662410c5aff8300c8784Craig Stout        super.onRowViewExpanded(holder, expanded);
41947520b68e50572a9775a662410c5aff8300c8784Craig Stout        ViewHolder vh = (ViewHolder) holder;
420a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        if (getRowHeight() != getExpandedRowHeight()) {
421a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn            int newHeight = expanded ? getExpandedRowHeight() : getRowHeight();
422a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn            vh.getGridView().setRowHeight(newHeight);
423a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        }
4244cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        setVerticalPadding(vh);
42547520b68e50572a9775a662410c5aff8300c8784Craig Stout        updateFooterViewSwitcher(vh);
42647520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
42747520b68e50572a9775a662410c5aff8300c8784Craig Stout
42847520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
429cb13a318e577e14461eb008071dddf762847de42Dake Gu    protected void onBindRowViewHolder(RowPresenter.ViewHolder holder, Object item) {
430cb13a318e577e14461eb008071dddf762847de42Dake Gu        super.onBindRowViewHolder(holder, item);
431cb13a318e577e14461eb008071dddf762847de42Dake Gu        ViewHolder vh = (ViewHolder) holder;
43247520b68e50572a9775a662410c5aff8300c8784Craig Stout        ListRow rowItem = (ListRow) item;
43347520b68e50572a9775a662410c5aff8300c8784Craig Stout        vh.mItemBridgeAdapter.setAdapter(rowItem.getAdapter());
43447520b68e50572a9775a662410c5aff8300c8784Craig Stout        vh.mGridView.setAdapter(vh.mItemBridgeAdapter);
43547520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
43647520b68e50572a9775a662410c5aff8300c8784Craig Stout
43747520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
438cb13a318e577e14461eb008071dddf762847de42Dake Gu    protected void onUnbindRowViewHolder(RowPresenter.ViewHolder holder) {
4395358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout        ViewHolder vh = (ViewHolder) holder;
4405358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout        vh.mGridView.setAdapter(null);
4415358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout        vh.mItemBridgeAdapter.clear();
442cb13a318e577e14461eb008071dddf762847de42Dake Gu        super.onUnbindRowViewHolder(holder);
44347520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
44447520b68e50572a9775a662410c5aff8300c8784Craig Stout
445cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    /**
446cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * ListRowPresenter overrides the default select effect of {@link RowPresenter}
447cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * and return false.
448cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     */
449cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    @Override
450cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    public final boolean isUsingDefaultSelectEffect() {
451cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        return false;
452cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
453cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
454cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    /**
455cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * Returns true so that default select effect is applied to each individual
456cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * child of {@link HorizontalGridView}.  Subclass may return false to disable
457cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * the default implementation.
458cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * @see #onSelectLevelChanged(RowPresenter.ViewHolder)
459cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     */
460cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    public boolean isUsingDefaultListSelectEffect() {
461cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        return true;
462cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
463cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
464cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    /**
465dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu     * Returns true if SDK >= 18, where default shadow
466892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * is applied to each individual child of {@link HorizontalGridView}.
467892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * Subclass may return false to disable.
468892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     */
469892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    public boolean isUsingDefaultShadow() {
470dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu        return ShadowOverlayContainer.supportsShadow();
471892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
472892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
473892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    /**
4740fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu     * Returns true if SDK >= L, where Z shadow is enabled so that Z order is enabled
4750fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu     * on each child of horizontal list.   If subclass returns false in isUsingDefaultShadow()
4760fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu     * and does not use Z-shadow on SDK >= L, it should override isUsingZOrder() return false.
4770fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu     */
4780fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu    public boolean isUsingZOrder() {
4790fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu        return ShadowHelper.getInstance().usesZShadow();
4800fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu    }
4810fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu
4820fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu    /**
483892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * Enable or disable child shadow.
484892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * This is not only for enable/disable default shadow implementation but also subclass must
485892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * respect this flag.
486892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     */
487892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    public final void setShadowEnabled(boolean enabled) {
488892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        mShadowEnabled = enabled;
489892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
490892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
491892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    /**
492892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * Returns true if child shadow is enabled.
493892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * This is not only for enable/disable default shadow implementation but also subclass must
494892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * respect this flag.
495892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     */
496892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    public final boolean getShadowEnabled() {
497892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        return mShadowEnabled;
498892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
499892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
5004f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout    /**
5014f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout     * Enables or disabled rounded corners on children of this row.
5024f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout     * Supported on Android SDK >= L.
5034f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout     */
5044f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout    public final void enableChildRoundedCorners(boolean enable) {
5054f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout        mRoundedCornersEnabled = enable;
5064f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout    }
5074f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout
5084f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout    /**
5094f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout     * Returns true if rounded corners are enabled for children of this row.
5104f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout     */
5114f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout    public final boolean areChildRoundedCornersEnabled() {
5124f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout        return mRoundedCornersEnabled;
5134f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout    }
5144f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout
515892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    final boolean needsDefaultShadow() {
516892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        return isUsingDefaultShadow() && getShadowEnabled();
517892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
518892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
519892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    @Override
520892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    public boolean canDrawOutOfBounds() {
521892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        return needsDefaultShadow();
522892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
523892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
524892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    /**
525cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * Applies select level to header and draw a default color dim over each child
526cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * of {@link HorizontalGridView}.
527cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * <p>
528cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * Subclass may override this method.  A subclass
529cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * needs to call super.onSelectLevelChanged() for applying header select level
530cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * and optionally applying a default select level to each child view of
531cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * {@link HorizontalGridView} if {@link #isUsingDefaultListSelectEffect()}
532cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * is true.  Subclass may override {@link #isUsingDefaultListSelectEffect()} to return
533cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * false and deal with the individual item select level by itself.
534cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * </p>
535cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     */
536cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    @Override
537cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    protected void onSelectLevelChanged(RowPresenter.ViewHolder holder) {
538cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        super.onSelectLevelChanged(holder);
539cb13a318e577e14461eb008071dddf762847de42Dake Gu        if (needsDefaultListSelectEffect()) {
540cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu            ViewHolder vh = (ViewHolder) holder;
541892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            int dimmedColor = vh.mColorDimmer.getPaint().getColor();
542892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            for (int i = 0, count = vh.mGridView.getChildCount(); i < count; i++) {
543dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu                ShadowOverlayContainer wrapper = (ShadowOverlayContainer) vh.mGridView.getChildAt(i);
544dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu                wrapper.setOverlayColor(dimmedColor);
545cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu            }
5469240e796bc63422c28f2707840bd99c48573279bDake Gu            if (vh.mGridView.getFadingLeftEdge()) {
5479240e796bc63422c28f2707840bd99c48573279bDake Gu                vh.mGridView.invalidate();
5489240e796bc63422c28f2707840bd99c48573279bDake Gu            }
549cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        }
550cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
551cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
552709bb7083a089e788d84ffa81f2c4f60a1bc8cf2Dake Gu    @Override
553709bb7083a089e788d84ffa81f2c4f60a1bc8cf2Dake Gu    public void freeze(RowPresenter.ViewHolder holder, boolean freeze) {
554709bb7083a089e788d84ffa81f2c4f60a1bc8cf2Dake Gu        ViewHolder vh = (ViewHolder) holder;
555709bb7083a089e788d84ffa81f2c4f60a1bc8cf2Dake Gu        vh.mGridView.setScrollEnabled(!freeze);
556709bb7083a089e788d84ffa81f2c4f60a1bc8cf2Dake Gu    }
557709bb7083a089e788d84ffa81f2c4f60a1bc8cf2Dake Gu
558c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    @Override
5593f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    public void setEntranceTransitionState(RowPresenter.ViewHolder holder,
5603f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu            boolean afterEntrance) {
5613f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        super.setEntranceTransitionState(holder, afterEntrance);
562c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        ((ViewHolder) holder).mGridView.setChildrenVisibility(
5633f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu                afterEntrance? View.VISIBLE : View.INVISIBLE);
564c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
56547520b68e50572a9775a662410c5aff8300c8784Craig Stout}
566