ListRowPresenter.java revision a4560456facaa3dd341a7ab2f372f655d46f7ee6
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
1647520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport java.util.ArrayList;
1747520b68e50572a9775a662410c5aff8300c8784Craig Stout
18892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.content.Context;
199240e796bc63422c28f2707840bd99c48573279bDake Guimport android.content.res.TypedArray;
20cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Guimport android.graphics.Canvas;
21892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.support.v17.leanback.R;
22cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Guimport android.support.v17.leanback.graphics.ColorOverlayDimmer;
2347520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.support.v17.leanback.widget.Presenter.ViewHolder;
24cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Guimport android.support.v7.widget.RecyclerView;
25892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.util.AttributeSet;
2647520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.View;
2747520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.ViewGroup;
28892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.view.ViewGroup.LayoutParams;
29892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.widget.FrameLayout;
3047520b68e50572a9775a662410c5aff8300c8784Craig Stout
3147520b68e50572a9775a662410c5aff8300c8784Craig Stout/**
327aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * ListRowPresenter renders {@link ListRow} using a
33cb13a318e577e14461eb008071dddf762847de42Dake Gu * {@link HorizontalGridView} hosted in a {@link ListRowView}.
347aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu *
357aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * <h3>Hover card</h3>
3647520b68e50572a9775a662410c5aff8300c8784Craig Stout * Optionally, {@link #setHoverCardPresenterSelector(PresenterSelector)} can be used to
3747520b68e50572a9775a662410c5aff8300c8784Craig Stout * display a view for the currently focused list item below the rendered
3847520b68e50572a9775a662410c5aff8300c8784Craig Stout * list. This view is known as a hover card.
397aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu *
407aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * <h3>Selection animation</h3>
417aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * ListRowPresenter disables {@link RowPresenter}'s default dimming effect and draw
427aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * a dim overlay on top of each individual child items.  Subclass may override and disable
437aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * {@link #isUsingDefaultListSelectEffect()} and write its own dim effect in
447aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * {@link #onSelectLevelChanged(RowPresenter.ViewHolder)}.
45dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu *
46dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * <h3>Shadow</h3>
47dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * ListRowPresenter applies a default shadow to child of each view.  Call
48dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * {@link #setShadowEnabled(boolean)} to disable shadow.  Subclass may override and return
49dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * false in {@link #isUsingDefaultShadow()} and replace with its own shadow implementation.
5047520b68e50572a9775a662410c5aff8300c8784Craig Stout */
5147520b68e50572a9775a662410c5aff8300c8784Craig Stoutpublic class ListRowPresenter extends RowPresenter {
5247520b68e50572a9775a662410c5aff8300c8784Craig Stout
5347520b68e50572a9775a662410c5aff8300c8784Craig Stout    private static final String TAG = "ListRowPresenter";
5447520b68e50572a9775a662410c5aff8300c8784Craig Stout    private static final boolean DEBUG = false;
5547520b68e50572a9775a662410c5aff8300c8784Craig Stout
5647520b68e50572a9775a662410c5aff8300c8784Craig Stout    public static class ViewHolder extends RowPresenter.ViewHolder {
5747520b68e50572a9775a662410c5aff8300c8784Craig Stout        final ListRowPresenter mListRowPresenter;
5847520b68e50572a9775a662410c5aff8300c8784Craig Stout        final HorizontalGridView mGridView;
5947520b68e50572a9775a662410c5aff8300c8784Craig Stout        final ItemBridgeAdapter mItemBridgeAdapter = new ItemBridgeAdapter();
6047520b68e50572a9775a662410c5aff8300c8784Craig Stout        final HorizontalHoverCardSwitcher mHoverCardViewSwitcher = new HorizontalHoverCardSwitcher();
61cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        final ColorOverlayDimmer mColorDimmer;
6247520b68e50572a9775a662410c5aff8300c8784Craig Stout
6347520b68e50572a9775a662410c5aff8300c8784Craig Stout        public ViewHolder(View rootView, HorizontalGridView gridView, ListRowPresenter p) {
6447520b68e50572a9775a662410c5aff8300c8784Craig Stout            super(rootView);
6547520b68e50572a9775a662410c5aff8300c8784Craig Stout            mGridView = gridView;
6647520b68e50572a9775a662410c5aff8300c8784Craig Stout            mListRowPresenter = p;
67cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu            mColorDimmer = ColorOverlayDimmer.createDefault(rootView.getContext());
6847520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
6947520b68e50572a9775a662410c5aff8300c8784Craig Stout
7047520b68e50572a9775a662410c5aff8300c8784Craig Stout        public final ListRowPresenter getListRowPresenter() {
7147520b68e50572a9775a662410c5aff8300c8784Craig Stout            return mListRowPresenter;
7247520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
7347520b68e50572a9775a662410c5aff8300c8784Craig Stout
7447520b68e50572a9775a662410c5aff8300c8784Craig Stout        public final HorizontalGridView getGridView() {
7547520b68e50572a9775a662410c5aff8300c8784Craig Stout            return mGridView;
7647520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
7747520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
7847520b68e50572a9775a662410c5aff8300c8784Craig Stout
79a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    private int mRowHeight;
80a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    private int mExpandedRowHeight;
8147520b68e50572a9775a662410c5aff8300c8784Craig Stout    private PresenterSelector mHoverCardPresenterSelector;
82b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    private int mZoomFactor;
83892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    private boolean mShadowEnabled = true;
849240e796bc63422c28f2707840bd99c48573279bDake Gu    private int mBrowseRowsFadingEdgeLength = -1;
85b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout
86b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    /**
87b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     * Constructs a ListRowPresenter with defaults.
88739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Uses {@link FocusHighlight#ZOOM_FACTOR_MEDIUM} for focus zooming.
89b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     */
90b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    public ListRowPresenter() {
91739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        this(FocusHighlight.ZOOM_FACTOR_MEDIUM);
92b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    }
93b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout
94b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    /**
95b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     * Constructs a ListRowPresenter with the given parameters.
96b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     *
97b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     * @param zoomFactor Controls the zoom factor used when an item view is focused. One of
98739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_NONE},
99739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_SMALL},
100739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_MEDIUM},
101739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_LARGE}
102b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     */
103b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    public ListRowPresenter(int zoomFactor) {
104b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout        mZoomFactor = zoomFactor;
105b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    }
106b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout
107b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    /**
108a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     * Sets the row height in pixels for rows created by this Presenter. Rows
109a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     * created before calling this method will not be updated.
110a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     *
111a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     * @param rowHeight The row height in pixels to use for rows created by this
112a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     *        Presenter, or 0 to use the default height.
113a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     */
114a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    public void setRowHeight(int rowHeight) {
115a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        mRowHeight = rowHeight;
116a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    }
117a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn
118a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    /**
119a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     * Returns the row height in pixels for rows created by this Presenter.
120a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     */
121a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    public int getRowHeight() {
122a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        return mRowHeight;
123a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    }
124a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn
125a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    /**
126a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     * Sets the expanded row height in pixels for rows created by this
127a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     * Presenter. If not set, expanded rows have the same height as unexpanded
128a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     * rows.
129a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     *
130a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     * @param rowHeight The row height in pixels to use for expanded rows
131a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     *        created by this Presenter, or 0 to use the default height.
132a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     */
133a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    public void setExpandedRowHeight(int rowHeight) {
134a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        mExpandedRowHeight = rowHeight;
135a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    }
136a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn
137a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    /**
138a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     * Returns the expanded row height in pixels for rows created by this
139a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     * Presenter.
140a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     */
141a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    public int getExpandedRowHeight() {
142a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        return mExpandedRowHeight > 0 ? mExpandedRowHeight : mRowHeight;
143a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    }
144a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn
145a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    /**
146b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     * Returns the zoom factor used for focus highlighting.
147b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     */
148b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    public final int getZoomFactor() {
149b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout        return mZoomFactor;
150b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    }
15147520b68e50572a9775a662410c5aff8300c8784Craig Stout
152892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    private ItemBridgeAdapter.Wrapper mCardWrapper = new ItemBridgeAdapter.Wrapper() {
153892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        @Override
154892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        public View createWrapper(View root) {
155dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu            ShadowOverlayContainer wrapper = new ShadowOverlayContainer(root.getContext());
156892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            wrapper.setLayoutParams(
157892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                    new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
158cb13a318e577e14461eb008071dddf762847de42Dake Gu            wrapper.initialize(needsDefaultShadow(), needsDefaultListSelectEffect());
159892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            return wrapper;
160892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        }
161892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        @Override
162892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        public void wrap(View wrapper, View wrapped) {
163dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu            ((ShadowOverlayContainer) wrapper).wrap(wrapped);
164892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        }
165892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    };
166892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
16747520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
16847520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected void initializeRowViewHolder(RowPresenter.ViewHolder holder) {
16947520b68e50572a9775a662410c5aff8300c8784Craig Stout        super.initializeRowViewHolder(holder);
17047520b68e50572a9775a662410c5aff8300c8784Craig Stout        final ViewHolder rowViewHolder = (ViewHolder) holder;
171c4b1a043ab39a881b2a05d50e93c35e6f6ebfffbDake Gu        if (needsDefaultListSelectEffect() || needsDefaultShadow()) {
172892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            rowViewHolder.mItemBridgeAdapter.setWrapper(mCardWrapper);
173892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        }
174cb13a318e577e14461eb008071dddf762847de42Dake Gu        if (needsDefaultListSelectEffect()) {
175dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu            ShadowOverlayContainer.prepareParentForShadow(rowViewHolder.mGridView);
176892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            ((ViewGroup) rowViewHolder.view).setClipChildren(false);
177cb13a318e577e14461eb008071dddf762847de42Dake Gu            if (rowViewHolder.mContainerViewHolder != null) {
178cb13a318e577e14461eb008071dddf762847de42Dake Gu                ((ViewGroup) rowViewHolder.mContainerViewHolder.view).setClipChildren(false);
179cb13a318e577e14461eb008071dddf762847de42Dake Gu            }
180cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        }
181b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout        FocusHighlightHelper.setupBrowseItemFocusHighlight(rowViewHolder.mItemBridgeAdapter, mZoomFactor);
18247520b68e50572a9775a662410c5aff8300c8784Craig Stout        rowViewHolder.mGridView.setOnChildSelectedListener(
18347520b68e50572a9775a662410c5aff8300c8784Craig Stout                new OnChildSelectedListener() {
18447520b68e50572a9775a662410c5aff8300c8784Craig Stout            @Override
18547520b68e50572a9775a662410c5aff8300c8784Craig Stout            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
18647520b68e50572a9775a662410c5aff8300c8784Craig Stout                selectChildView(rowViewHolder, view);
18747520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
18847520b68e50572a9775a662410c5aff8300c8784Craig Stout        });
189892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        rowViewHolder.mItemBridgeAdapter.setAdapterListener(
190892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                new ItemBridgeAdapter.AdapterListener() {
191892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            @Override
192892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            public void onCreate(final ItemBridgeAdapter.ViewHolder viewHolder) {
193892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                // Only when having an OnItemClickListner, we will attach the OnClickListener.
194892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                if (getOnItemClickedListener() != null) {
19547520b68e50572a9775a662410c5aff8300c8784Craig Stout                    viewHolder.mHolder.view.setOnClickListener(new View.OnClickListener() {
19647520b68e50572a9775a662410c5aff8300c8784Craig Stout                        @Override
19747520b68e50572a9775a662410c5aff8300c8784Craig Stout                        public void onClick(View v) {
19847520b68e50572a9775a662410c5aff8300c8784Craig Stout                            ItemBridgeAdapter.ViewHolder ibh = (ItemBridgeAdapter.ViewHolder)
199892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                                    rowViewHolder.mGridView.getChildViewHolder(viewHolder.itemView);
20047520b68e50572a9775a662410c5aff8300c8784Craig Stout                            if (getOnItemClickedListener() != null) {
20147520b68e50572a9775a662410c5aff8300c8784Craig Stout                                getOnItemClickedListener().onItemClicked(ibh.mItem,
20247520b68e50572a9775a662410c5aff8300c8784Craig Stout                                        (ListRow) rowViewHolder.mRow);
20347520b68e50572a9775a662410c5aff8300c8784Craig Stout                            }
20447520b68e50572a9775a662410c5aff8300c8784Craig Stout                        }
20547520b68e50572a9775a662410c5aff8300c8784Craig Stout                    });
20647520b68e50572a9775a662410c5aff8300c8784Craig Stout                }
207892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            }
208892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
209892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            @Override
21029246e5ca814f17dcf368eeacd1b44a329592ae0Dake Gu            public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) {
211dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu                if (viewHolder.itemView instanceof ShadowOverlayContainer) {
212892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                    int dimmedColor = rowViewHolder.mColorDimmer.getPaint().getColor();
213dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu                    ((ShadowOverlayContainer) viewHolder.itemView).setOverlayColor(dimmedColor);
214892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                }
2154df06cbe8f6dd087fc8f1068faa77923cb297365Tim Kilbourn                viewHolder.itemView.setActivated(rowViewHolder.mExpanded);
216892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            }
217892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        });
21847520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
21947520b68e50572a9775a662410c5aff8300c8784Craig Stout
220cb13a318e577e14461eb008071dddf762847de42Dake Gu    final boolean needsDefaultListSelectEffect() {
221cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        return isUsingDefaultListSelectEffect() && getSelectEffectEnabled();
222cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
223cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
22447520b68e50572a9775a662410c5aff8300c8784Craig Stout    /**
22547520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Set {@link PresenterSelector} used for showing a select object in a hover card.
22647520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
22747520b68e50572a9775a662410c5aff8300c8784Craig Stout    public final void setHoverCardPresenterSelector(PresenterSelector selector) {
22847520b68e50572a9775a662410c5aff8300c8784Craig Stout        mHoverCardPresenterSelector = selector;
22947520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
23047520b68e50572a9775a662410c5aff8300c8784Craig Stout
23147520b68e50572a9775a662410c5aff8300c8784Craig Stout    /**
23247520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Get {@link PresenterSelector} used for showing a select object in a hover card.
23347520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
23447520b68e50572a9775a662410c5aff8300c8784Craig Stout    public final PresenterSelector getHoverCardPresenterSelector() {
23547520b68e50572a9775a662410c5aff8300c8784Craig Stout        return mHoverCardPresenterSelector;
23647520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
23747520b68e50572a9775a662410c5aff8300c8784Craig Stout
23847520b68e50572a9775a662410c5aff8300c8784Craig Stout    /*
23947520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Perform operations when a child of horizontal grid view is selected.
24047520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
24147520b68e50572a9775a662410c5aff8300c8784Craig Stout    private void selectChildView(ViewHolder rowViewHolder, View view) {
24247520b68e50572a9775a662410c5aff8300c8784Craig Stout        ItemBridgeAdapter.ViewHolder ibh = null;
24347520b68e50572a9775a662410c5aff8300c8784Craig Stout        if (view != null) {
24447520b68e50572a9775a662410c5aff8300c8784Craig Stout            ibh = (ItemBridgeAdapter.ViewHolder)
24547520b68e50572a9775a662410c5aff8300c8784Craig Stout                    rowViewHolder.mGridView.getChildViewHolder(view);
24647520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
24747520b68e50572a9775a662410c5aff8300c8784Craig Stout        if (view == null) {
24847520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (mHoverCardPresenterSelector != null) {
24947520b68e50572a9775a662410c5aff8300c8784Craig Stout                rowViewHolder.mHoverCardViewSwitcher.unselect();
25047520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
25147520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (getOnItemSelectedListener() != null) {
25247520b68e50572a9775a662410c5aff8300c8784Craig Stout                getOnItemSelectedListener().onItemSelected(null, rowViewHolder.mRow);
25347520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
25447520b68e50572a9775a662410c5aff8300c8784Craig Stout        } else if (rowViewHolder.mExpanded && rowViewHolder.mSelected) {
25547520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (mHoverCardPresenterSelector != null) {
25647520b68e50572a9775a662410c5aff8300c8784Craig Stout                rowViewHolder.mHoverCardViewSwitcher.select(rowViewHolder.mGridView, view,
25747520b68e50572a9775a662410c5aff8300c8784Craig Stout                        ibh.mItem);
25847520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
25947520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (getOnItemSelectedListener() != null) {
26047520b68e50572a9775a662410c5aff8300c8784Craig Stout                getOnItemSelectedListener().onItemSelected(ibh.mItem, rowViewHolder.mRow);
26147520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
26247520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
26347520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
26447520b68e50572a9775a662410c5aff8300c8784Craig Stout
26547520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
26647520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) {
267cb13a318e577e14461eb008071dddf762847de42Dake Gu        ListRowView rowView = new ListRowView(parent.getContext());
2689240e796bc63422c28f2707840bd99c48573279bDake Gu        setupFadingEffect(rowView);
269a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        if (mRowHeight > 0) {
270a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn            rowView.getGridView().setRowHeight(mRowHeight);
271a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        }
27247520b68e50572a9775a662410c5aff8300c8784Craig Stout        return new ViewHolder(rowView, rowView.getGridView(), this);
27347520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
27447520b68e50572a9775a662410c5aff8300c8784Craig Stout
27547520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
27647520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected void onRowViewSelected(RowPresenter.ViewHolder holder, boolean selected) {
27747520b68e50572a9775a662410c5aff8300c8784Craig Stout        updateFooterViewSwitcher((ViewHolder) holder);
27847520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
27947520b68e50572a9775a662410c5aff8300c8784Craig Stout
28047520b68e50572a9775a662410c5aff8300c8784Craig Stout    /*
28147520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Show or hide hover card when row selection or expanded state is changed.
28247520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
28347520b68e50572a9775a662410c5aff8300c8784Craig Stout    private void updateFooterViewSwitcher(ViewHolder vh) {
28447520b68e50572a9775a662410c5aff8300c8784Craig Stout        if (vh.mExpanded && vh.mSelected) {
28547520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (mHoverCardPresenterSelector != null) {
28647520b68e50572a9775a662410c5aff8300c8784Craig Stout                vh.mHoverCardViewSwitcher.init((ViewGroup) vh.view,
28747520b68e50572a9775a662410c5aff8300c8784Craig Stout                        mHoverCardPresenterSelector);
28847520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
28902e411c2c69d20aab138f1a162a24ea650eff7a1Dake Gu            ItemBridgeAdapter.ViewHolder ibh = (ItemBridgeAdapter.ViewHolder)
29002e411c2c69d20aab138f1a162a24ea650eff7a1Dake Gu                    vh.mGridView.findViewHolderForPosition(
29102e411c2c69d20aab138f1a162a24ea650eff7a1Dake Gu                            vh.mGridView.getSelectedPosition());
29202e411c2c69d20aab138f1a162a24ea650eff7a1Dake Gu            selectChildView(vh, ibh == null ? null : ibh.itemView);
29347520b68e50572a9775a662410c5aff8300c8784Craig Stout        } else {
29447520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (mHoverCardPresenterSelector != null) {
29547520b68e50572a9775a662410c5aff8300c8784Craig Stout                vh.mHoverCardViewSwitcher.clear();
29647520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
29747520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
29847520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
29947520b68e50572a9775a662410c5aff8300c8784Craig Stout
3009240e796bc63422c28f2707840bd99c48573279bDake Gu    private void setupFadingEffect(ListRowView rowView) {
3019240e796bc63422c28f2707840bd99c48573279bDake Gu        // content is completely faded at 1/2 padding of left, fading length is 1/2 of padding.
3029240e796bc63422c28f2707840bd99c48573279bDake Gu        HorizontalGridView gridView = rowView.getGridView();
3039240e796bc63422c28f2707840bd99c48573279bDake Gu        if (mBrowseRowsFadingEdgeLength < 0) {
3049240e796bc63422c28f2707840bd99c48573279bDake Gu            TypedArray ta = gridView.getContext()
3059240e796bc63422c28f2707840bd99c48573279bDake Gu                    .obtainStyledAttributes(R.styleable.LeanbackTheme);
3069240e796bc63422c28f2707840bd99c48573279bDake Gu            mBrowseRowsFadingEdgeLength = (int) ta.getDimension(
3079240e796bc63422c28f2707840bd99c48573279bDake Gu                    R.styleable.LeanbackTheme_browseRowsFadingEdgeLength, 0);
3089240e796bc63422c28f2707840bd99c48573279bDake Gu            ta.recycle();
30947520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
3109240e796bc63422c28f2707840bd99c48573279bDake Gu        gridView.setFadingLeftEdgeLength(mBrowseRowsFadingEdgeLength);
31147520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
31247520b68e50572a9775a662410c5aff8300c8784Craig Stout
31347520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
31447520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected void onRowViewExpanded(RowPresenter.ViewHolder holder, boolean expanded) {
31547520b68e50572a9775a662410c5aff8300c8784Craig Stout        super.onRowViewExpanded(holder, expanded);
31647520b68e50572a9775a662410c5aff8300c8784Craig Stout        ViewHolder vh = (ViewHolder) holder;
317a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        if (getRowHeight() != getExpandedRowHeight()) {
318a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn            int newHeight = expanded ? getExpandedRowHeight() : getRowHeight();
319a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn            vh.getGridView().setRowHeight(newHeight);
320a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        }
3219240e796bc63422c28f2707840bd99c48573279bDake Gu        vh.getGridView().setFadingLeftEdge(!expanded);
32247520b68e50572a9775a662410c5aff8300c8784Craig Stout        updateFooterViewSwitcher(vh);
32347520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
32447520b68e50572a9775a662410c5aff8300c8784Craig Stout
32547520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
326cb13a318e577e14461eb008071dddf762847de42Dake Gu    protected void onBindRowViewHolder(RowPresenter.ViewHolder holder, Object item) {
327cb13a318e577e14461eb008071dddf762847de42Dake Gu        super.onBindRowViewHolder(holder, item);
328cb13a318e577e14461eb008071dddf762847de42Dake Gu        ViewHolder vh = (ViewHolder) holder;
32947520b68e50572a9775a662410c5aff8300c8784Craig Stout        ListRow rowItem = (ListRow) item;
33047520b68e50572a9775a662410c5aff8300c8784Craig Stout        vh.mItemBridgeAdapter.clear();
33147520b68e50572a9775a662410c5aff8300c8784Craig Stout        vh.mItemBridgeAdapter.setAdapter(rowItem.getAdapter());
33247520b68e50572a9775a662410c5aff8300c8784Craig Stout        vh.mGridView.setAdapter(vh.mItemBridgeAdapter);
33347520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
33447520b68e50572a9775a662410c5aff8300c8784Craig Stout
33547520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
336cb13a318e577e14461eb008071dddf762847de42Dake Gu    protected void onUnbindRowViewHolder(RowPresenter.ViewHolder holder) {
337cb13a318e577e14461eb008071dddf762847de42Dake Gu        ((ViewHolder) holder).mGridView.setAdapter(null);
338cb13a318e577e14461eb008071dddf762847de42Dake Gu        super.onUnbindRowViewHolder(holder);
33947520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
34047520b68e50572a9775a662410c5aff8300c8784Craig Stout
341cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    /**
342cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * ListRowPresenter overrides the default select effect of {@link RowPresenter}
343cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * and return false.
344cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     */
345cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    @Override
346cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    public final boolean isUsingDefaultSelectEffect() {
347cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        return false;
348cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
349cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
350cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    /**
351cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * Returns true so that default select effect is applied to each individual
352cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * child of {@link HorizontalGridView}.  Subclass may return false to disable
353cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * the default implementation.
354cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * @see #onSelectLevelChanged(RowPresenter.ViewHolder)
355cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     */
356cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    public boolean isUsingDefaultListSelectEffect() {
357cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        return true;
358cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
359cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
360cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    /**
361dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu     * Returns true if SDK >= 18, where default shadow
362892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * is applied to each individual child of {@link HorizontalGridView}.
363892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * Subclass may return false to disable.
364892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     */
365892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    public boolean isUsingDefaultShadow() {
366dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu        return ShadowOverlayContainer.supportsShadow();
367892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
368892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
369892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    /**
370892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * Enable or disable child shadow.
371892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * This is not only for enable/disable default shadow implementation but also subclass must
372892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * respect this flag.
373892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     */
374892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    public final void setShadowEnabled(boolean enabled) {
375892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        mShadowEnabled = enabled;
376892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
377892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
378892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    /**
379892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * Returns true if child shadow is enabled.
380892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * This is not only for enable/disable default shadow implementation but also subclass must
381892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * respect this flag.
382892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     */
383892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    public final boolean getShadowEnabled() {
384892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        return mShadowEnabled;
385892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
386892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
387892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    final boolean needsDefaultShadow() {
388892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        return isUsingDefaultShadow() && getShadowEnabled();
389892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
390892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
391892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    @Override
392892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    public boolean canDrawOutOfBounds() {
393892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        return needsDefaultShadow();
394892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
395892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
396892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    /**
397cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * Applies select level to header and draw a default color dim over each child
398cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * of {@link HorizontalGridView}.
399cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * <p>
400cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * Subclass may override this method.  A subclass
401cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * needs to call super.onSelectLevelChanged() for applying header select level
402cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * and optionally applying a default select level to each child view of
403cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * {@link HorizontalGridView} if {@link #isUsingDefaultListSelectEffect()}
404cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * is true.  Subclass may override {@link #isUsingDefaultListSelectEffect()} to return
405cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * false and deal with the individual item select level by itself.
406cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * </p>
407cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     */
408cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    @Override
409cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    protected void onSelectLevelChanged(RowPresenter.ViewHolder holder) {
410cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        super.onSelectLevelChanged(holder);
411cb13a318e577e14461eb008071dddf762847de42Dake Gu        if (needsDefaultListSelectEffect()) {
412cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu            ViewHolder vh = (ViewHolder) holder;
413cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu            vh.mColorDimmer.setActiveLevel(holder.mSelectLevel);
414892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            int dimmedColor = vh.mColorDimmer.getPaint().getColor();
415892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            for (int i = 0, count = vh.mGridView.getChildCount(); i < count; i++) {
416dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu                ShadowOverlayContainer wrapper = (ShadowOverlayContainer) vh.mGridView.getChildAt(i);
417dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu                wrapper.setOverlayColor(dimmedColor);
418cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu            }
4199240e796bc63422c28f2707840bd99c48573279bDake Gu            if (vh.mGridView.getFadingLeftEdge()) {
4209240e796bc63422c28f2707840bd99c48573279bDake Gu                vh.mGridView.invalidate();
4219240e796bc63422c28f2707840bd99c48573279bDake Gu            }
422cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        }
423cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
424cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
42547520b68e50572a9775a662410c5aff8300c8784Craig Stout}
426