ListRowPresenter.java revision dfd01bbadc107b6b3b2081ddb0236128c425f380
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;
19cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Guimport android.graphics.Canvas;
20892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.support.v17.leanback.R;
21cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Guimport android.support.v17.leanback.graphics.ColorOverlayDimmer;
2247520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.support.v17.leanback.widget.Presenter.ViewHolder;
23cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Guimport android.support.v7.widget.RecyclerView;
24892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.util.AttributeSet;
2547520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.View;
2647520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.ViewGroup;
27892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.view.ViewGroup.LayoutParams;
28892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.widget.FrameLayout;
2947520b68e50572a9775a662410c5aff8300c8784Craig Stout
3047520b68e50572a9775a662410c5aff8300c8784Craig Stout/**
317aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * ListRowPresenter renders {@link ListRow} using a
327aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * {@link HorizontalGridView} hosted in a {@link BrowseRowView}.
337aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu *
347aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * <h3>Hover card</h3>
3547520b68e50572a9775a662410c5aff8300c8784Craig Stout * Optionally, {@link #setHoverCardPresenterSelector(PresenterSelector)} can be used to
3647520b68e50572a9775a662410c5aff8300c8784Craig Stout * display a view for the currently focused list item below the rendered
3747520b68e50572a9775a662410c5aff8300c8784Craig Stout * list. This view is known as a hover card.
387aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu *
397aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * <h3>Selection animation</h3>
407aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * ListRowPresenter disables {@link RowPresenter}'s default dimming effect and draw
417aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * a dim overlay on top of each individual child items.  Subclass may override and disable
427aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * {@link #isUsingDefaultListSelectEffect()} and write its own dim effect in
437aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * {@link #onSelectLevelChanged(RowPresenter.ViewHolder)}.
44dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu *
45dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * <h3>Shadow</h3>
46dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * ListRowPresenter applies a default shadow to child of each view.  Call
47dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * {@link #setShadowEnabled(boolean)} to disable shadow.  Subclass may override and return
48dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * false in {@link #isUsingDefaultShadow()} and replace with its own shadow implementation.
4947520b68e50572a9775a662410c5aff8300c8784Craig Stout */
5047520b68e50572a9775a662410c5aff8300c8784Craig Stoutpublic class ListRowPresenter extends RowPresenter {
5147520b68e50572a9775a662410c5aff8300c8784Craig Stout
5247520b68e50572a9775a662410c5aff8300c8784Craig Stout    private static final String TAG = "ListRowPresenter";
5347520b68e50572a9775a662410c5aff8300c8784Craig Stout    private static final boolean DEBUG = false;
5447520b68e50572a9775a662410c5aff8300c8784Craig Stout
5562d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn    /**
5662d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn     * No zoom factor.
5762d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn     * @deprecated Use {@link FocusHighlight#ZOOM_FACTOR_NONE} instead.
5862d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn     */
5962d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn    @Deprecated
6062d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn    public static final int ZOOM_FACTOR_NONE = FocusHighlight.ZOOM_FACTOR_NONE;
6162d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn
6262d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn    /**
6362d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn     * A small zoom factor, recommended for large item views.
6462d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn     * @deprecated Use {@link FocusHighlight#ZOOM_FACTOR_SMALL} instead.
6562d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn     */
6662d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn    @Deprecated
6762d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn    public static final int ZOOM_FACTOR_SMALL = FocusHighlight.ZOOM_FACTOR_SMALL;
6862d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn
6962d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn    /**
7062d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn     * A medium zoom factor, recommended for medium sized item views.
7162d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn     * @deprecated Use {@link FocusHighlight#ZOOM_FACTOR_MEDIUM} instead.
7262d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn     */
7362d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn    @Deprecated
7462d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn    public static final int ZOOM_FACTOR_MEDIUM = FocusHighlight.ZOOM_FACTOR_MEDIUM;
7562d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn
7662d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn    /**
7762d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn     * A large zoom factor, recommended for small item views.
7862d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn     * @deprecated Use {@link FocusHighlight#ZOOM_FACTOR_LARGE} instead.
7962d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn     */
8062d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn    @Deprecated
8162d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn    public static final int ZOOM_FACTOR_LARGE = FocusHighlight.ZOOM_FACTOR_LARGE;
8262d5de70439cb859525e45310b5ac4dbbfe420f2Tim Kilbourn
8347520b68e50572a9775a662410c5aff8300c8784Craig Stout    public static class ViewHolder extends RowPresenter.ViewHolder {
8447520b68e50572a9775a662410c5aff8300c8784Craig Stout        final ListRowPresenter mListRowPresenter;
8547520b68e50572a9775a662410c5aff8300c8784Craig Stout        final HorizontalGridView mGridView;
8647520b68e50572a9775a662410c5aff8300c8784Craig Stout        final ItemBridgeAdapter mItemBridgeAdapter = new ItemBridgeAdapter();
8747520b68e50572a9775a662410c5aff8300c8784Craig Stout        final HorizontalHoverCardSwitcher mHoverCardViewSwitcher = new HorizontalHoverCardSwitcher();
88cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        final ColorOverlayDimmer mColorDimmer;
8947520b68e50572a9775a662410c5aff8300c8784Craig Stout
9047520b68e50572a9775a662410c5aff8300c8784Craig Stout        public ViewHolder(View rootView, HorizontalGridView gridView, ListRowPresenter p) {
9147520b68e50572a9775a662410c5aff8300c8784Craig Stout            super(rootView);
9247520b68e50572a9775a662410c5aff8300c8784Craig Stout            mGridView = gridView;
9347520b68e50572a9775a662410c5aff8300c8784Craig Stout            mListRowPresenter = p;
94cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu            mColorDimmer = ColorOverlayDimmer.createDefault(rootView.getContext());
9547520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
9647520b68e50572a9775a662410c5aff8300c8784Craig Stout
9747520b68e50572a9775a662410c5aff8300c8784Craig Stout        public final ListRowPresenter getListRowPresenter() {
9847520b68e50572a9775a662410c5aff8300c8784Craig Stout            return mListRowPresenter;
9947520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
10047520b68e50572a9775a662410c5aff8300c8784Craig Stout
10147520b68e50572a9775a662410c5aff8300c8784Craig Stout        public final HorizontalGridView getGridView() {
10247520b68e50572a9775a662410c5aff8300c8784Craig Stout            return mGridView;
10347520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
10447520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
10547520b68e50572a9775a662410c5aff8300c8784Craig Stout
10647520b68e50572a9775a662410c5aff8300c8784Craig Stout    private PresenterSelector mHoverCardPresenterSelector;
107b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    private int mZoomFactor;
108892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    private boolean mShadowEnabled = true;
109b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout
110b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    /**
111b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     * Constructs a ListRowPresenter with defaults.
112739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     * Uses {@link FocusHighlight#ZOOM_FACTOR_MEDIUM} for focus zooming.
113b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     */
114b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    public ListRowPresenter() {
115739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        this(FocusHighlight.ZOOM_FACTOR_MEDIUM);
116b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    }
117b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout
118b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    /**
119b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     * Constructs a ListRowPresenter with the given parameters.
120b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     *
121b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     * @param zoomFactor Controls the zoom factor used when an item view is focused. One of
122739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_NONE},
123739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_SMALL},
124739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_MEDIUM},
125739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_LARGE}
126b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     */
127b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    public ListRowPresenter(int zoomFactor) {
128b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout        mZoomFactor = zoomFactor;
129b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    }
130b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout
131b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    /**
132b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     * Returns the zoom factor used for focus highlighting.
133b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     */
134b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    public final int getZoomFactor() {
135b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout        return mZoomFactor;
136b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    }
13747520b68e50572a9775a662410c5aff8300c8784Craig Stout
138892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    private ItemBridgeAdapter.Wrapper mCardWrapper = new ItemBridgeAdapter.Wrapper() {
139892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        @Override
140892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        public View createWrapper(View root) {
141dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu            ShadowOverlayContainer wrapper = new ShadowOverlayContainer(root.getContext());
142892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            wrapper.setLayoutParams(
143892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                    new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
144892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            wrapper.initialize(needsDefaultShadow(), needsDefaultSelectEffect());
145892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            return wrapper;
146892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        }
147892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        @Override
148892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        public void wrap(View wrapper, View wrapped) {
149dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu            ((ShadowOverlayContainer) wrapper).wrap(wrapped);
150892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        }
151892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    };
152892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
15347520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
15447520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected void initializeRowViewHolder(RowPresenter.ViewHolder holder) {
15547520b68e50572a9775a662410c5aff8300c8784Craig Stout        super.initializeRowViewHolder(holder);
15647520b68e50572a9775a662410c5aff8300c8784Craig Stout        final ViewHolder rowViewHolder = (ViewHolder) holder;
157892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        if (needsDefaultSelectEffect() || needsDefaultShadow()) {
158892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            rowViewHolder.mItemBridgeAdapter.setWrapper(mCardWrapper);
159892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        }
160892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        if (needsDefaultShadow()) {
161dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu            ShadowOverlayContainer.prepareParentForShadow(rowViewHolder.mGridView);
162892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            ((ViewGroup) rowViewHolder.view).setClipChildren(false);
163cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        }
164b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout        FocusHighlightHelper.setupBrowseItemFocusHighlight(rowViewHolder.mItemBridgeAdapter, mZoomFactor);
16547520b68e50572a9775a662410c5aff8300c8784Craig Stout        rowViewHolder.mGridView.setOnChildSelectedListener(
16647520b68e50572a9775a662410c5aff8300c8784Craig Stout                new OnChildSelectedListener() {
16747520b68e50572a9775a662410c5aff8300c8784Craig Stout            @Override
16847520b68e50572a9775a662410c5aff8300c8784Craig Stout            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
16947520b68e50572a9775a662410c5aff8300c8784Craig Stout                selectChildView(rowViewHolder, view);
17047520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
17147520b68e50572a9775a662410c5aff8300c8784Craig Stout        });
172892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        rowViewHolder.mItemBridgeAdapter.setAdapterListener(
173892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                new ItemBridgeAdapter.AdapterListener() {
174892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            @Override
175892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            public void onCreate(final ItemBridgeAdapter.ViewHolder viewHolder) {
176892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                // Only when having an OnItemClickListner, we will attach the OnClickListener.
177892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                if (getOnItemClickedListener() != null) {
17847520b68e50572a9775a662410c5aff8300c8784Craig Stout                    viewHolder.mHolder.view.setOnClickListener(new View.OnClickListener() {
17947520b68e50572a9775a662410c5aff8300c8784Craig Stout                        @Override
18047520b68e50572a9775a662410c5aff8300c8784Craig Stout                        public void onClick(View v) {
18147520b68e50572a9775a662410c5aff8300c8784Craig Stout                            ItemBridgeAdapter.ViewHolder ibh = (ItemBridgeAdapter.ViewHolder)
182892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                                    rowViewHolder.mGridView.getChildViewHolder(viewHolder.itemView);
18347520b68e50572a9775a662410c5aff8300c8784Craig Stout                            if (getOnItemClickedListener() != null) {
18447520b68e50572a9775a662410c5aff8300c8784Craig Stout                                getOnItemClickedListener().onItemClicked(ibh.mItem,
18547520b68e50572a9775a662410c5aff8300c8784Craig Stout                                        (ListRow) rowViewHolder.mRow);
18647520b68e50572a9775a662410c5aff8300c8784Craig Stout                            }
18747520b68e50572a9775a662410c5aff8300c8784Craig Stout                        }
18847520b68e50572a9775a662410c5aff8300c8784Craig Stout                    });
18947520b68e50572a9775a662410c5aff8300c8784Craig Stout                }
190892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            }
191892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
192892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            @Override
19329246e5ca814f17dcf368eeacd1b44a329592ae0Dake Gu            public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) {
194dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu                if (viewHolder.itemView instanceof ShadowOverlayContainer) {
195892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                    int dimmedColor = rowViewHolder.mColorDimmer.getPaint().getColor();
196dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu                    ((ShadowOverlayContainer) viewHolder.itemView).setOverlayColor(dimmedColor);
197892181367d658f347d00ea5e091aa31f086b2a20Dake Gu                }
198892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            }
199892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        });
20047520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
20147520b68e50572a9775a662410c5aff8300c8784Craig Stout
202892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    final boolean needsDefaultSelectEffect() {
203cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        return isUsingDefaultListSelectEffect() && getSelectEffectEnabled();
204cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
205cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
20647520b68e50572a9775a662410c5aff8300c8784Craig Stout    /**
20747520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Set {@link PresenterSelector} used for showing a select object in a hover card.
20847520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
20947520b68e50572a9775a662410c5aff8300c8784Craig Stout    public final void setHoverCardPresenterSelector(PresenterSelector selector) {
21047520b68e50572a9775a662410c5aff8300c8784Craig Stout        mHoverCardPresenterSelector = selector;
21147520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
21247520b68e50572a9775a662410c5aff8300c8784Craig Stout
21347520b68e50572a9775a662410c5aff8300c8784Craig Stout    /**
21447520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Get {@link PresenterSelector} used for showing a select object in a hover card.
21547520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
21647520b68e50572a9775a662410c5aff8300c8784Craig Stout    public final PresenterSelector getHoverCardPresenterSelector() {
21747520b68e50572a9775a662410c5aff8300c8784Craig Stout        return mHoverCardPresenterSelector;
21847520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
21947520b68e50572a9775a662410c5aff8300c8784Craig Stout
22047520b68e50572a9775a662410c5aff8300c8784Craig Stout    /*
22147520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Perform operations when a child of horizontal grid view is selected.
22247520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
22347520b68e50572a9775a662410c5aff8300c8784Craig Stout    private void selectChildView(ViewHolder rowViewHolder, View view) {
22447520b68e50572a9775a662410c5aff8300c8784Craig Stout        ItemBridgeAdapter.ViewHolder ibh = null;
22547520b68e50572a9775a662410c5aff8300c8784Craig Stout        if (view != null) {
22647520b68e50572a9775a662410c5aff8300c8784Craig Stout            ibh = (ItemBridgeAdapter.ViewHolder)
22747520b68e50572a9775a662410c5aff8300c8784Craig Stout                    rowViewHolder.mGridView.getChildViewHolder(view);
22847520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
22947520b68e50572a9775a662410c5aff8300c8784Craig Stout        if (view == null) {
23047520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (mHoverCardPresenterSelector != null) {
23147520b68e50572a9775a662410c5aff8300c8784Craig Stout                rowViewHolder.mHoverCardViewSwitcher.unselect();
23247520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
23347520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (getOnItemSelectedListener() != null) {
23447520b68e50572a9775a662410c5aff8300c8784Craig Stout                getOnItemSelectedListener().onItemSelected(null, rowViewHolder.mRow);
23547520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
23647520b68e50572a9775a662410c5aff8300c8784Craig Stout        } else if (rowViewHolder.mExpanded && rowViewHolder.mSelected) {
23747520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (mHoverCardPresenterSelector != null) {
23847520b68e50572a9775a662410c5aff8300c8784Craig Stout                rowViewHolder.mHoverCardViewSwitcher.select(rowViewHolder.mGridView, view,
23947520b68e50572a9775a662410c5aff8300c8784Craig Stout                        ibh.mItem);
24047520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
24147520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (getOnItemSelectedListener() != null) {
24247520b68e50572a9775a662410c5aff8300c8784Craig Stout                getOnItemSelectedListener().onItemSelected(ibh.mItem, rowViewHolder.mRow);
24347520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
24447520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
24547520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
24647520b68e50572a9775a662410c5aff8300c8784Craig Stout
24747520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
24847520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) {
24947520b68e50572a9775a662410c5aff8300c8784Craig Stout        BrowseRowView rowView = new BrowseRowView(parent.getContext());
25047520b68e50572a9775a662410c5aff8300c8784Craig Stout        return new ViewHolder(rowView, rowView.getGridView(), this);
25147520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
25247520b68e50572a9775a662410c5aff8300c8784Craig Stout
25347520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
25447520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected void onRowViewSelected(RowPresenter.ViewHolder holder, boolean selected) {
25547520b68e50572a9775a662410c5aff8300c8784Craig Stout        updateFooterViewSwitcher((ViewHolder) holder);
25647520b68e50572a9775a662410c5aff8300c8784Craig Stout        updateInitialChildSelection((ViewHolder) holder);
25747520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
25847520b68e50572a9775a662410c5aff8300c8784Craig Stout
25947520b68e50572a9775a662410c5aff8300c8784Craig Stout    /*
26047520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Show or hide hover card when row selection or expanded state is changed.
26147520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
26247520b68e50572a9775a662410c5aff8300c8784Craig Stout    private void updateFooterViewSwitcher(ViewHolder vh) {
26347520b68e50572a9775a662410c5aff8300c8784Craig Stout        if (vh.mExpanded && vh.mSelected) {
26447520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (mHoverCardPresenterSelector != null) {
26547520b68e50572a9775a662410c5aff8300c8784Craig Stout                vh.mHoverCardViewSwitcher.init((ViewGroup) vh.view,
26647520b68e50572a9775a662410c5aff8300c8784Craig Stout                        mHoverCardPresenterSelector);
26747520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
26847520b68e50572a9775a662410c5aff8300c8784Craig Stout        } else {
26947520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (mHoverCardPresenterSelector != null) {
27047520b68e50572a9775a662410c5aff8300c8784Craig Stout                vh.mHoverCardViewSwitcher.clear();
27147520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
27247520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
27347520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
27447520b68e50572a9775a662410c5aff8300c8784Craig Stout
27547520b68e50572a9775a662410c5aff8300c8784Craig Stout    /*
27647520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Make initial child selection when row selection state is changed.
27747520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
27847520b68e50572a9775a662410c5aff8300c8784Craig Stout    private void updateInitialChildSelection(ViewHolder vh) {
27947520b68e50572a9775a662410c5aff8300c8784Craig Stout        if (vh.mExpanded && vh.mSelected) {
28047520b68e50572a9775a662410c5aff8300c8784Craig Stout            ItemBridgeAdapter.ViewHolder ibh = (ItemBridgeAdapter.ViewHolder)
28147520b68e50572a9775a662410c5aff8300c8784Craig Stout                    vh.mGridView.findViewHolderForPosition(
282025aa57d4fdd4e79289303c7dc54169311728f7bCraig Stout                            vh.mGridView.getSelectedPosition());
283892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            selectChildView(vh, ibh == null ? null : ibh.itemView);
28447520b68e50572a9775a662410c5aff8300c8784Craig Stout        } else {
28547520b68e50572a9775a662410c5aff8300c8784Craig Stout            selectChildView(vh, null);
28647520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
28747520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
28847520b68e50572a9775a662410c5aff8300c8784Craig Stout
28947520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
29047520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected void onRowViewExpanded(RowPresenter.ViewHolder holder, boolean expanded) {
29147520b68e50572a9775a662410c5aff8300c8784Craig Stout        super.onRowViewExpanded(holder, expanded);
29247520b68e50572a9775a662410c5aff8300c8784Craig Stout        ViewHolder vh = (ViewHolder) holder;
29347520b68e50572a9775a662410c5aff8300c8784Craig Stout        vh.mGridView.setClipToPadding(!expanded);
294db1e9bb04638eb6b0b16e849e433d1c3b6f4296cDake Gu        vh.mGridView.invalidate();
29547520b68e50572a9775a662410c5aff8300c8784Craig Stout        updateFooterViewSwitcher(vh);
29647520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
29747520b68e50572a9775a662410c5aff8300c8784Craig Stout
29847520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
29947520b68e50572a9775a662410c5aff8300c8784Craig Stout    public void onBindViewHolder(Presenter.ViewHolder holder, Object item) {
30047520b68e50572a9775a662410c5aff8300c8784Craig Stout        super.onBindViewHolder(holder, item);
30147520b68e50572a9775a662410c5aff8300c8784Craig Stout        ViewHolder vh = (ViewHolder)holder;
30247520b68e50572a9775a662410c5aff8300c8784Craig Stout        ListRow rowItem = (ListRow) item;
30347520b68e50572a9775a662410c5aff8300c8784Craig Stout        vh.mItemBridgeAdapter.clear();
30447520b68e50572a9775a662410c5aff8300c8784Craig Stout        vh.mItemBridgeAdapter.setAdapter(rowItem.getAdapter());
30547520b68e50572a9775a662410c5aff8300c8784Craig Stout        vh.mGridView.setAdapter(vh.mItemBridgeAdapter);
30647520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
30747520b68e50572a9775a662410c5aff8300c8784Craig Stout
30847520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
30947520b68e50572a9775a662410c5aff8300c8784Craig Stout    public void onUnbindViewHolder(Presenter.ViewHolder holder) {
31047520b68e50572a9775a662410c5aff8300c8784Craig Stout        ViewHolder vh = (ViewHolder)holder;
31147520b68e50572a9775a662410c5aff8300c8784Craig Stout        vh.mGridView.setAdapter(null);
31247520b68e50572a9775a662410c5aff8300c8784Craig Stout        super.onUnbindViewHolder(holder);
31347520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
31447520b68e50572a9775a662410c5aff8300c8784Craig Stout
315cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    /**
316cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * ListRowPresenter overrides the default select effect of {@link RowPresenter}
317cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * and return false.
318cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     */
319cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    @Override
320cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    public final boolean isUsingDefaultSelectEffect() {
321cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        return false;
322cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
323cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
324cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    /**
325cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * Returns true so that default select effect is applied to each individual
326cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * child of {@link HorizontalGridView}.  Subclass may return false to disable
327cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * the default implementation.
328cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * @see #onSelectLevelChanged(RowPresenter.ViewHolder)
329cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     */
330cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    public boolean isUsingDefaultListSelectEffect() {
331cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        return true;
332cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
333cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
334cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    /**
335dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu     * Returns true if SDK >= 18, where default shadow
336892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * is applied to each individual child of {@link HorizontalGridView}.
337892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * Subclass may return false to disable.
338892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     */
339892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    public boolean isUsingDefaultShadow() {
340dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu        return ShadowOverlayContainer.supportsShadow();
341892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
342892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
343892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    /**
344892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * Enable or disable child shadow.
345892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * This is not only for enable/disable default shadow implementation but also subclass must
346892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * respect this flag.
347892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     */
348892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    public final void setShadowEnabled(boolean enabled) {
349892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        mShadowEnabled = enabled;
350892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
351892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
352892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    /**
353892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * Returns true if child shadow is enabled.
354892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * This is not only for enable/disable default shadow implementation but also subclass must
355892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * respect this flag.
356892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     */
357892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    public final boolean getShadowEnabled() {
358892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        return mShadowEnabled;
359892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
360892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
361892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    final boolean needsDefaultShadow() {
362892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        return isUsingDefaultShadow() && getShadowEnabled();
363892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
364892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
365892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    @Override
366892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    public boolean canDrawOutOfBounds() {
367892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        return needsDefaultShadow();
368892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
369892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
370892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    /**
371cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * Applies select level to header and draw a default color dim over each child
372cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * of {@link HorizontalGridView}.
373cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * <p>
374cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * Subclass may override this method.  A subclass
375cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * needs to call super.onSelectLevelChanged() for applying header select level
376cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * and optionally applying a default select level to each child view of
377cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * {@link HorizontalGridView} if {@link #isUsingDefaultListSelectEffect()}
378cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * is true.  Subclass may override {@link #isUsingDefaultListSelectEffect()} to return
379cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * false and deal with the individual item select level by itself.
380cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * </p>
381cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     */
382cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    @Override
383cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    protected void onSelectLevelChanged(RowPresenter.ViewHolder holder) {
384cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        super.onSelectLevelChanged(holder);
385892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        if (needsDefaultSelectEffect()) {
386cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu            ViewHolder vh = (ViewHolder) holder;
387cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu            vh.mColorDimmer.setActiveLevel(holder.mSelectLevel);
388892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            int dimmedColor = vh.mColorDimmer.getPaint().getColor();
389892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            for (int i = 0, count = vh.mGridView.getChildCount(); i < count; i++) {
390dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu                ShadowOverlayContainer wrapper = (ShadowOverlayContainer) vh.mGridView.getChildAt(i);
391dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu                wrapper.setOverlayColor(dimmedColor);
392cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu            }
393cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        }
394cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
395cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
39647520b68e50572a9775a662410c5aff8300c8784Craig Stout}
397