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;
19f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stoutimport android.support.v17.leanback.system.Settings;
20afb203b71421cb0d477d4d470e852cc9647dde48Dake Guimport android.support.v17.leanback.transition.TransitionHelper;
21cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Guimport android.support.v7.widget.RecyclerView;
224cd4cce277571385f4d1a56d5348578c38368cbeCraig Stoutimport android.util.Log;
2360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stoutimport android.view.KeyEvent;
2447520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.View;
2547520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.ViewGroup;
2647520b68e50572a9775a662410c5aff8300c8784Craig Stout
27bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stoutimport java.util.HashMap;
28bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout
2947520b68e50572a9775a662410c5aff8300c8784Craig Stout/**
307aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * ListRowPresenter renders {@link ListRow} using a
31cb13a318e577e14461eb008071dddf762847de42Dake Gu * {@link HorizontalGridView} hosted in a {@link ListRowView}.
327aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu *
337aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * <h3>Hover card</h3>
3447520b68e50572a9775a662410c5aff8300c8784Craig Stout * Optionally, {@link #setHoverCardPresenterSelector(PresenterSelector)} can be used to
3547520b68e50572a9775a662410c5aff8300c8784Craig Stout * display a view for the currently focused list item below the rendered
3647520b68e50572a9775a662410c5aff8300c8784Craig Stout * list. This view is known as a hover card.
377aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu *
387aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * <h3>Selection animation</h3>
39a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * ListRowPresenter disables {@link RowPresenter}'s default dimming effect and draws
40a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * a dim overlay on each view individually.  A subclass may override and disable
417aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * {@link #isUsingDefaultListSelectEffect()} and write its own dim effect in
427aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * {@link #onSelectLevelChanged(RowPresenter.ViewHolder)}.
43dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu *
44dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * <h3>Shadow</h3>
45a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * ListRowPresenter applies a default shadow to each child view.  Call
46a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * {@link #setShadowEnabled(boolean)} to disable shadows.  A subclass may override and return
47dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * false in {@link #isUsingDefaultShadow()} and replace with its own shadow implementation.
4847520b68e50572a9775a662410c5aff8300c8784Craig Stout */
4947520b68e50572a9775a662410c5aff8300c8784Craig Stoutpublic class ListRowPresenter extends RowPresenter {
5047520b68e50572a9775a662410c5aff8300c8784Craig Stout
5147520b68e50572a9775a662410c5aff8300c8784Craig Stout    private static final String TAG = "ListRowPresenter";
5247520b68e50572a9775a662410c5aff8300c8784Craig Stout    private static final boolean DEBUG = false;
5347520b68e50572a9775a662410c5aff8300c8784Craig Stout
54bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    private static final int DEFAULT_RECYCLED_POOL_SIZE = 24;
55bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout
56a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout    /**
57a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * ViewHolder for the ListRowPresenter.
58a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     */
5947520b68e50572a9775a662410c5aff8300c8784Craig Stout    public static class ViewHolder extends RowPresenter.ViewHolder {
6047520b68e50572a9775a662410c5aff8300c8784Craig Stout        final ListRowPresenter mListRowPresenter;
6147520b68e50572a9775a662410c5aff8300c8784Craig Stout        final HorizontalGridView mGridView;
6271fddded48048acfa744ac352166770c91a1c2b1Dake Gu        ItemBridgeAdapter mItemBridgeAdapter;
6347520b68e50572a9775a662410c5aff8300c8784Craig Stout        final HorizontalHoverCardSwitcher mHoverCardViewSwitcher = new HorizontalHoverCardSwitcher();
64e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu        final int mPaddingTop;
65e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu        final int mPaddingBottom;
66e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu        final int mPaddingLeft;
67e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu        final int mPaddingRight;
6847520b68e50572a9775a662410c5aff8300c8784Craig Stout
6947520b68e50572a9775a662410c5aff8300c8784Craig Stout        public ViewHolder(View rootView, HorizontalGridView gridView, ListRowPresenter p) {
7047520b68e50572a9775a662410c5aff8300c8784Craig Stout            super(rootView);
7147520b68e50572a9775a662410c5aff8300c8784Craig Stout            mGridView = gridView;
7247520b68e50572a9775a662410c5aff8300c8784Craig Stout            mListRowPresenter = p;
73e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu            mPaddingTop = mGridView.getPaddingTop();
74e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu            mPaddingBottom = mGridView.getPaddingBottom();
75e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu            mPaddingLeft = mGridView.getPaddingLeft();
76e43e9266c4b7e4902fefb5d2a0cacca90a3d2681Dake Gu            mPaddingRight = mGridView.getPaddingRight();
7747520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
7847520b68e50572a9775a662410c5aff8300c8784Craig Stout
7960f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu        /**
8060f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         * Gets ListRowPresenter that creates this ViewHolder.
8160f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         * @return ListRowPresenter that creates this ViewHolder.
8260f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         */
8347520b68e50572a9775a662410c5aff8300c8784Craig Stout        public final ListRowPresenter getListRowPresenter() {
8447520b68e50572a9775a662410c5aff8300c8784Craig Stout            return mListRowPresenter;
8547520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
8647520b68e50572a9775a662410c5aff8300c8784Craig Stout
8760f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu        /**
8860f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         * Gets HorizontalGridView that shows a list of items.
8960f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         * @return HorizontalGridView that shows a list of items.
9060f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         */
9147520b68e50572a9775a662410c5aff8300c8784Craig Stout        public final HorizontalGridView getGridView() {
9247520b68e50572a9775a662410c5aff8300c8784Craig Stout            return mGridView;
9347520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
949de682083d3da5b1127969ee1fd7b74561aa9acdCraig Stout
9560f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu        /**
9660f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         * Gets ItemBridgeAdapter that creates the list of items.
9760f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         * @return ItemBridgeAdapter that creates the list of items.
9860f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         */
999de682083d3da5b1127969ee1fd7b74561aa9acdCraig Stout        public final ItemBridgeAdapter getBridgeAdapter() {
1009de682083d3da5b1127969ee1fd7b74561aa9acdCraig Stout            return mItemBridgeAdapter;
1019de682083d3da5b1127969ee1fd7b74561aa9acdCraig Stout        }
10260f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu
10360f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu        /**
10460f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         * Gets selected item position in adapter.
10560f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         * @return Selected item position in adapter.
10660f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         */
10760f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu        public int getSelectedPosition() {
10860f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu            return mGridView.getSelectedPosition();
10960f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu        }
11060f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu
11160f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu        /**
11260f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         * Gets ViewHolder at a position in adapter.  Returns null if the item does not exist
11360f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         * or the item is not bound to a view.
11460f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         * @param position Position of the item in adapter.
11560f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         * @return ViewHolder bounds to the item.
11660f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu         */
11760f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu        public Presenter.ViewHolder getItemViewHolder(int position) {
11860f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu            ItemBridgeAdapter.ViewHolder ibvh = (ItemBridgeAdapter.ViewHolder) mGridView
11960f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu                    .findViewHolderForAdapterPosition(position);
12060f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu            if (ibvh == null) {
12160f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu                return null;
12260f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu            }
12360f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu            return ibvh.getViewHolder();
12460f531e3d9667db9afe091f5a7979410eb7a0b48Dake Gu        }
12547520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
12647520b68e50572a9775a662410c5aff8300c8784Craig Stout
127cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu    /**
128cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu     * A task on the ListRowPresenter.ViewHolder that can select an item by position in the
129cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu     * HorizontalGridView and perform an optional item task on it.
130cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu     */
131cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu    public static class SelectItemViewHolderTask extends Presenter.ViewHolderTask {
132cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu
133cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        private int mItemPosition;
134cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        private boolean mSmoothScroll = true;
135cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        private Presenter.ViewHolderTask mItemTask;
136cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu
137cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        public SelectItemViewHolderTask(int itemPosition) {
138cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu            setItemPosition(itemPosition);
139cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        }
140cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu
141cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        /**
142cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         * Sets the adapter position of item to select.
143cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         * @param itemPosition Position of the item in adapter.
144cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         */
145cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        public void setItemPosition(int itemPosition) {
146cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu            mItemPosition = itemPosition;
147cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        }
148cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu
149cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        /**
150cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         * Returns the adapter position of item to select.
151cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         * @return The adapter position of item to select.
152cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         */
153cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        public int getItemPosition() {
154cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu            return mItemPosition;
155cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        }
156cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu
157cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        /**
158cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         * Sets smooth scrolling to the item or jump to the item without scrolling.  By default it is
159cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         * true.
160cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         * @param smoothScroll True for smooth scrolling to the item, false otherwise.
161cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         */
162cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        public void setSmoothScroll(boolean smoothScroll) {
163cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu            mSmoothScroll = smoothScroll;
164cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        }
165cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu
166cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        /**
167cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         * Returns true if smooth scrolling to the item false otherwise.  By default it is true.
168cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         * @return True for smooth scrolling to the item, false otherwise.
169cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         */
170cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        public boolean isSmoothScroll() {
171cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu            return mSmoothScroll;
172cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        }
173cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu
174cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        /**
175cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         * Returns optional task to run when the item is selected, null for no task.
176cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         * @return Optional task to run when the item is selected, null for no task.
177cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         */
178cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        public Presenter.ViewHolderTask getItemTask() {
179cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu            return mItemTask;
180cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        }
181cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu
182cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        /**
183cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         * Sets task to run when the item is selected, null for no task.
184cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         * @param itemTask Optional task to run when the item is selected, null for no task.
185cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu         */
186cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        public void setItemTask(Presenter.ViewHolderTask itemTask) {
187cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu            mItemTask = itemTask;
188cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        }
189cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu
190cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        @Override
191cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        public void run(Presenter.ViewHolder holder) {
192cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu            if (holder instanceof ListRowPresenter.ViewHolder) {
193cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                HorizontalGridView gridView = ((ListRowPresenter.ViewHolder) holder).getGridView();
194cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                android.support.v17.leanback.widget.ViewHolderTask task = null;
195cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                if (mItemTask != null) {
196cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                    task = new android.support.v17.leanback.widget.ViewHolderTask() {
197cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                        final Presenter.ViewHolderTask itemTask = mItemTask;
198cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                        @Override
199cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                        public void run(RecyclerView.ViewHolder rvh) {
200cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                            ItemBridgeAdapter.ViewHolder ibvh = (ItemBridgeAdapter.ViewHolder) rvh;
201cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                            itemTask.run(ibvh.getViewHolder());
202cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                        }
203cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                    };
204cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                }
205cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                if (isSmoothScroll()) {
206cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                    gridView.setSelectedPositionSmooth(mItemPosition, task);
207cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                } else {
208cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                    gridView.setSelectedPosition(mItemPosition, task);
209cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu                }
210cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu            }
211cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu        }
212cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu    }
213cff6e470de4a0b2ed1dec944bdc848bd26f852f6Dake Gu
21471fddded48048acfa744ac352166770c91a1c2b1Dake Gu    class ListRowPresenterItemBridgeAdapter extends ItemBridgeAdapter {
21571fddded48048acfa744ac352166770c91a1c2b1Dake Gu        ListRowPresenter.ViewHolder mRowViewHolder;
21671fddded48048acfa744ac352166770c91a1c2b1Dake Gu
21771fddded48048acfa744ac352166770c91a1c2b1Dake Gu        ListRowPresenterItemBridgeAdapter(ListRowPresenter.ViewHolder rowViewHolder) {
21871fddded48048acfa744ac352166770c91a1c2b1Dake Gu            mRowViewHolder = rowViewHolder;
21971fddded48048acfa744ac352166770c91a1c2b1Dake Gu        }
22071fddded48048acfa744ac352166770c91a1c2b1Dake Gu
22171fddded48048acfa744ac352166770c91a1c2b1Dake Gu        @Override
222254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu        protected void onCreate(ItemBridgeAdapter.ViewHolder viewHolder) {
223afb203b71421cb0d477d4d470e852cc9647dde48Dake Gu            if (viewHolder.itemView instanceof ViewGroup) {
2248403619efebe94666c0615c3fc85080a303acf80Dake Gu                TransitionHelper.setTransitionGroup((ViewGroup) viewHolder.itemView, true);
225afb203b71421cb0d477d4d470e852cc9647dde48Dake Gu            }
226254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu            if (mShadowOverlayHelper != null) {
227254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu                mShadowOverlayHelper.onViewCreated(viewHolder.itemView);
228254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu            }
229254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu        }
230254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu
231254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu        @Override
23271fddded48048acfa744ac352166770c91a1c2b1Dake Gu        public void onBind(final ItemBridgeAdapter.ViewHolder viewHolder) {
23371fddded48048acfa744ac352166770c91a1c2b1Dake Gu            // Only when having an OnItemClickListner, we will attach the OnClickListener.
2343a5038bd0fefa5628a31a21422bf2126c53472a9Craig Stout            if (mRowViewHolder.getOnItemViewClickedListener() != null) {
23571fddded48048acfa744ac352166770c91a1c2b1Dake Gu                viewHolder.mHolder.view.setOnClickListener(new View.OnClickListener() {
23671fddded48048acfa744ac352166770c91a1c2b1Dake Gu                    @Override
23771fddded48048acfa744ac352166770c91a1c2b1Dake Gu                    public void onClick(View v) {
23871fddded48048acfa744ac352166770c91a1c2b1Dake Gu                        ItemBridgeAdapter.ViewHolder ibh = (ItemBridgeAdapter.ViewHolder)
23971fddded48048acfa744ac352166770c91a1c2b1Dake Gu                                mRowViewHolder.mGridView.getChildViewHolder(viewHolder.itemView);
2403a5038bd0fefa5628a31a21422bf2126c53472a9Craig Stout                        if (mRowViewHolder.getOnItemViewClickedListener() != null) {
2413a5038bd0fefa5628a31a21422bf2126c53472a9Craig Stout                            mRowViewHolder.getOnItemViewClickedListener().onItemClicked(viewHolder.mHolder,
24271fddded48048acfa744ac352166770c91a1c2b1Dake Gu                                    ibh.mItem, mRowViewHolder, (ListRow) mRowViewHolder.mRow);
24371fddded48048acfa744ac352166770c91a1c2b1Dake Gu                        }
24471fddded48048acfa744ac352166770c91a1c2b1Dake Gu                    }
24571fddded48048acfa744ac352166770c91a1c2b1Dake Gu                });
24671fddded48048acfa744ac352166770c91a1c2b1Dake Gu            }
24771fddded48048acfa744ac352166770c91a1c2b1Dake Gu        }
24871fddded48048acfa744ac352166770c91a1c2b1Dake Gu
24971fddded48048acfa744ac352166770c91a1c2b1Dake Gu        @Override
25071fddded48048acfa744ac352166770c91a1c2b1Dake Gu        public void onUnbind(ItemBridgeAdapter.ViewHolder viewHolder) {
2513a5038bd0fefa5628a31a21422bf2126c53472a9Craig Stout            if (mRowViewHolder.getOnItemViewClickedListener() != null) {
25271fddded48048acfa744ac352166770c91a1c2b1Dake Gu                viewHolder.mHolder.view.setOnClickListener(null);
25371fddded48048acfa744ac352166770c91a1c2b1Dake Gu            }
25471fddded48048acfa744ac352166770c91a1c2b1Dake Gu        }
25571fddded48048acfa744ac352166770c91a1c2b1Dake Gu
25671fddded48048acfa744ac352166770c91a1c2b1Dake Gu        @Override
25771fddded48048acfa744ac352166770c91a1c2b1Dake Gu        public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) {
258254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu            if (mShadowOverlayHelper != null && mShadowOverlayHelper.needsOverlay()) {
25971fddded48048acfa744ac352166770c91a1c2b1Dake Gu                int dimmedColor = mRowViewHolder.mColorDimmer.getPaint().getColor();
26085833087b2288e0f002de6b4ebcbc0564839a217Dake Gu                mShadowOverlayHelper.setOverlayColor(viewHolder.itemView, dimmedColor);
26171fddded48048acfa744ac352166770c91a1c2b1Dake Gu            }
26271fddded48048acfa744ac352166770c91a1c2b1Dake Gu            mRowViewHolder.syncActivatedStatus(viewHolder.itemView);
26371fddded48048acfa744ac352166770c91a1c2b1Dake Gu        }
26471fddded48048acfa744ac352166770c91a1c2b1Dake Gu
26571fddded48048acfa744ac352166770c91a1c2b1Dake Gu        @Override
26671fddded48048acfa744ac352166770c91a1c2b1Dake Gu        public void onAddPresenter(Presenter presenter, int type) {
26771fddded48048acfa744ac352166770c91a1c2b1Dake Gu            mRowViewHolder.getGridView().getRecycledViewPool().setMaxRecycledViews(
26871fddded48048acfa744ac352166770c91a1c2b1Dake Gu                    type, getRecycledPoolSize(presenter));
26971fddded48048acfa744ac352166770c91a1c2b1Dake Gu        }
27071fddded48048acfa744ac352166770c91a1c2b1Dake Gu    }
27171fddded48048acfa744ac352166770c91a1c2b1Dake Gu
272b9fd330aaaede57fd2ff0ac1289429aab7a3cf42susnata    private int mNumRows = 1;
273a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    private int mRowHeight;
274a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    private int mExpandedRowHeight;
27547520b68e50572a9775a662410c5aff8300c8784Craig Stout    private PresenterSelector mHoverCardPresenterSelector;
27641ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield    private int mFocusZoomFactor;
27741ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield    private boolean mUseFocusDimmer;
278892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    private boolean mShadowEnabled = true;
2799240e796bc63422c28f2707840bd99c48573279bDake Gu    private int mBrowseRowsFadingEdgeLength = -1;
2804f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout    private boolean mRoundedCornersEnabled = true;
28185833087b2288e0f002de6b4ebcbc0564839a217Dake Gu    private boolean mKeepChildForeground = true;
282bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    private HashMap<Presenter, Integer> mRecycledPoolSize = new HashMap<Presenter, Integer>();
283254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu    private ShadowOverlayHelper mShadowOverlayHelper;
28485833087b2288e0f002de6b4ebcbc0564839a217Dake Gu    private ItemBridgeAdapter.Wrapper mShadowOverlayWrapper;
285b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout
2864cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    private static int sSelectedRowTopPadding;
2874cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    private static int sExpandedSelectedRowTopPadding;
2884cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    private static int sExpandedRowNoHovercardBottomPadding;
2894cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout
290b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    /**
291b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     * Constructs a ListRowPresenter with defaults.
29241ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     * Uses {@link FocusHighlight#ZOOM_FACTOR_MEDIUM} for focus zooming and
29341ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     * disabled dimming on focus.
294b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     */
295b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    public ListRowPresenter() {
296739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout        this(FocusHighlight.ZOOM_FACTOR_MEDIUM);
297b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    }
298b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout
299b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    /**
300b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     * Constructs a ListRowPresenter with the given parameters.
301b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     *
30241ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     * @param focusZoomFactor Controls the zoom factor used when an item view is focused. One of
303739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_NONE},
304739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_SMALL},
305575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_XSMALL},
306739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_MEDIUM},
307739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout     *         {@link FocusHighlight#ZOOM_FACTOR_LARGE}
30841ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     * Dimming on focus defaults to disabled.
309b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     */
31041ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield    public ListRowPresenter(int focusZoomFactor) {
31141ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield        this(focusZoomFactor, false);
31241ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield    }
31341ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield
31441ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield    /**
31541ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     * Constructs a ListRowPresenter with the given parameters.
31641ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     *
31741ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     * @param focusZoomFactor Controls the zoom factor used when an item view is focused. One of
31841ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     *         {@link FocusHighlight#ZOOM_FACTOR_NONE},
31941ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     *         {@link FocusHighlight#ZOOM_FACTOR_SMALL},
32041ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     *         {@link FocusHighlight#ZOOM_FACTOR_XSMALL},
32141ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     *         {@link FocusHighlight#ZOOM_FACTOR_MEDIUM},
32241ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     *         {@link FocusHighlight#ZOOM_FACTOR_LARGE}
32341ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     * @param useFocusDimmer determines if the FocusHighlighter will use the dimmer
32441ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     */
32541ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield    public ListRowPresenter(int focusZoomFactor, boolean useFocusDimmer) {
32641ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield        if (!FocusHighlightHelper.isValidZoomIndex(focusZoomFactor)) {
327575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout            throw new IllegalArgumentException("Unhandled zoom factor");
328575dc8a5a5c023aee0c0ec297a7d357685cf49e9Craig Stout        }
32941ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield        mFocusZoomFactor = focusZoomFactor;
33041ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield        mUseFocusDimmer = useFocusDimmer;
331b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    }
332b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout
333b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    /**
334f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * Sets the row height for rows created by this Presenter. Rows
335a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     * created before calling this method will not be updated.
336a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     *
337f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * @param rowHeight Row height in pixels, or WRAP_CONTENT, or 0
338f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * to use the default height.
339a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     */
340a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    public void setRowHeight(int rowHeight) {
341a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        mRowHeight = rowHeight;
342a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    }
343a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn
344a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    /**
345f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * Returns the row height for list rows created by this Presenter.
346a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     */
347a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    public int getRowHeight() {
348a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        return mRowHeight;
349a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    }
350a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn
351a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    /**
352f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * Sets the expanded row height for rows created by this Presenter.
353f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * If not set, expanded rows have the same height as unexpanded
354a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     * rows.
355a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     *
356f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * @param rowHeight The row height in to use when the row is expanded,
357f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     *        in pixels, or WRAP_CONTENT, or 0 to use the default.
358a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     */
359a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    public void setExpandedRowHeight(int rowHeight) {
360a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        mExpandedRowHeight = rowHeight;
361a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    }
362a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn
363a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    /**
364f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout     * Returns the expanded row height for rows created by this Presenter.
365a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn     */
366a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    public int getExpandedRowHeight() {
367f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout        return mExpandedRowHeight != 0 ? mExpandedRowHeight : mRowHeight;
368a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    }
369a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn
370a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn    /**
371b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     * Returns the zoom factor used for focus highlighting.
372b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout     */
37341ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield    public final int getFocusZoomFactor() {
37441ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield        return mFocusZoomFactor;
37541ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield    }
376a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout
37741ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield    /**
37841ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     * Returns the zoom factor used for focus highlighting.
37941ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     * @deprecated use {@link #getFocusZoomFactor} instead.
38041ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     */
381a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout    @Deprecated
382a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout    public final int getZoomFactor() {
38341ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield        return mFocusZoomFactor;
38441ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield    }
38541ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield
38641ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield    /**
38741ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     * Returns true if the focus dimmer is used for focus highlighting; false otherwise.
38841ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield     */
38941ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield    public final boolean isFocusDimmerUsed() {
39041ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield        return mUseFocusDimmer;
391b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout    }
39247520b68e50572a9775a662410c5aff8300c8784Craig Stout
393b9fd330aaaede57fd2ff0ac1289429aab7a3cf42susnata    /**
394b9fd330aaaede57fd2ff0ac1289429aab7a3cf42susnata     * Sets the numbers of rows for rendering the list of items. By default, it is
395b9fd330aaaede57fd2ff0ac1289429aab7a3cf42susnata     * set to 1.
396b9fd330aaaede57fd2ff0ac1289429aab7a3cf42susnata     */
397b9fd330aaaede57fd2ff0ac1289429aab7a3cf42susnata    public void setNumRows(int numRows) {
398b9fd330aaaede57fd2ff0ac1289429aab7a3cf42susnata        this.mNumRows = numRows;
399b9fd330aaaede57fd2ff0ac1289429aab7a3cf42susnata    }
400b9fd330aaaede57fd2ff0ac1289429aab7a3cf42susnata
40147520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
40247520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected void initializeRowViewHolder(RowPresenter.ViewHolder holder) {
40347520b68e50572a9775a662410c5aff8300c8784Craig Stout        super.initializeRowViewHolder(holder);
40447520b68e50572a9775a662410c5aff8300c8784Craig Stout        final ViewHolder rowViewHolder = (ViewHolder) holder;
405254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu        Context context = holder.view.getContext();
406254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu        if (mShadowOverlayHelper == null) {
40785833087b2288e0f002de6b4ebcbc0564839a217Dake Gu            mShadowOverlayHelper = new ShadowOverlayHelper.Builder()
40885833087b2288e0f002de6b4ebcbc0564839a217Dake Gu                    .needsOverlay(needsDefaultListSelectEffect())
40985833087b2288e0f002de6b4ebcbc0564839a217Dake Gu                    .needsShadow(needsDefaultShadow())
41085833087b2288e0f002de6b4ebcbc0564839a217Dake Gu                    .needsRoundedCorner(areChildRoundedCornersEnabled())
41185833087b2288e0f002de6b4ebcbc0564839a217Dake Gu                    .preferZOrder(isUsingZOrder(context))
41285833087b2288e0f002de6b4ebcbc0564839a217Dake Gu                    .keepForegroundDrawable(mKeepChildForeground)
41385833087b2288e0f002de6b4ebcbc0564839a217Dake Gu                    .options(createShadowOverlayOptions())
41485833087b2288e0f002de6b4ebcbc0564839a217Dake Gu                    .build(context);
41585833087b2288e0f002de6b4ebcbc0564839a217Dake Gu            if (mShadowOverlayHelper.needsWrapper()) {
41685833087b2288e0f002de6b4ebcbc0564839a217Dake Gu                mShadowOverlayWrapper = new ItemBridgeAdapterShadowOverlayWrapper(
41785833087b2288e0f002de6b4ebcbc0564839a217Dake Gu                        mShadowOverlayHelper);
41885833087b2288e0f002de6b4ebcbc0564839a217Dake Gu            }
419cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        }
420254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu        rowViewHolder.mItemBridgeAdapter = new ListRowPresenterItemBridgeAdapter(rowViewHolder);
421254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu        // set wrapper if needed
42285833087b2288e0f002de6b4ebcbc0564839a217Dake Gu        rowViewHolder.mItemBridgeAdapter.setWrapper(mShadowOverlayWrapper);
423254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu        mShadowOverlayHelper.prepareParentForShadow(rowViewHolder.mGridView);
424254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu
42546e7de54775fc37dc51041629c79249e6dae3242Dake Gu        FocusHighlightHelper.setupBrowseItemFocusHighlight(rowViewHolder.mItemBridgeAdapter,
42641ad8b4ffe5adbc5c8568d359786a67a4937964dJohn Butterfield                mFocusZoomFactor, mUseFocusDimmer);
427254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu        rowViewHolder.mGridView.setFocusDrawingOrderEnabled(mShadowOverlayHelper.getShadowType()
428254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu                == ShadowOverlayHelper.SHADOW_STATIC);
42947520b68e50572a9775a662410c5aff8300c8784Craig Stout        rowViewHolder.mGridView.setOnChildSelectedListener(
43047520b68e50572a9775a662410c5aff8300c8784Craig Stout                new OnChildSelectedListener() {
43147520b68e50572a9775a662410c5aff8300c8784Craig Stout            @Override
43247520b68e50572a9775a662410c5aff8300c8784Craig Stout            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
4330246318f27a905a31df5a8af445cfe67d31dfb68Dake Gu                selectChildView(rowViewHolder, view, true);
43447520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
43547520b68e50572a9775a662410c5aff8300c8784Craig Stout        });
43660bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout        rowViewHolder.mGridView.setOnUnhandledKeyListener(
43760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout                new BaseGridView.OnUnhandledKeyListener() {
43860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout            @Override
43960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout            public boolean onUnhandledKey(KeyEvent event) {
44060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout                if (rowViewHolder.getOnKeyListener() != null &&
44160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout                        rowViewHolder.getOnKeyListener().onKey(
44260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout                                rowViewHolder.view, event.getKeyCode(), event)) {
44360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout                    return true;
44460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout                }
44560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout                return false;
44647520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
44747520b68e50572a9775a662410c5aff8300c8784Craig Stout        });
448b9fd330aaaede57fd2ff0ac1289429aab7a3cf42susnata        rowViewHolder.mGridView.setNumRows(mNumRows);
44947520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
45047520b68e50572a9775a662410c5aff8300c8784Craig Stout
451cb13a318e577e14461eb008071dddf762847de42Dake Gu    final boolean needsDefaultListSelectEffect() {
452cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        return isUsingDefaultListSelectEffect() && getSelectEffectEnabled();
453cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
454cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
45547520b68e50572a9775a662410c5aff8300c8784Craig Stout    /**
456bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout     * Sets the recycled pool size for the given presenter.
457bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout     */
458bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    public void setRecycledPoolSize(Presenter presenter, int size) {
459bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout        mRecycledPoolSize.put(presenter, size);
460bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    }
461bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout
462bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    /**
463bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout     * Returns the recycled pool size for the given presenter.
464bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout     */
465bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    public int getRecycledPoolSize(Presenter presenter) {
466bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout        return mRecycledPoolSize.containsKey(presenter) ? mRecycledPoolSize.get(presenter) :
467bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout                DEFAULT_RECYCLED_POOL_SIZE;
468bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    }
469bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout
470bb370eee93bfe84a6e14be0e8476f48c32e2dcb0Craig Stout    /**
471a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Sets the {@link PresenterSelector} used for showing a select object in a hover card.
47247520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
47347520b68e50572a9775a662410c5aff8300c8784Craig Stout    public final void setHoverCardPresenterSelector(PresenterSelector selector) {
47447520b68e50572a9775a662410c5aff8300c8784Craig Stout        mHoverCardPresenterSelector = selector;
47547520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
47647520b68e50572a9775a662410c5aff8300c8784Craig Stout
47747520b68e50572a9775a662410c5aff8300c8784Craig Stout    /**
478a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Returns the {@link PresenterSelector} used for showing a select object in a hover card.
47947520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
48047520b68e50572a9775a662410c5aff8300c8784Craig Stout    public final PresenterSelector getHoverCardPresenterSelector() {
48147520b68e50572a9775a662410c5aff8300c8784Craig Stout        return mHoverCardPresenterSelector;
48247520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
48347520b68e50572a9775a662410c5aff8300c8784Craig Stout
48447520b68e50572a9775a662410c5aff8300c8784Craig Stout    /*
48547520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Perform operations when a child of horizontal grid view is selected.
48647520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
4870246318f27a905a31df5a8af445cfe67d31dfb68Dake Gu    private void selectChildView(ViewHolder rowViewHolder, View view, boolean fireEvent) {
48847520b68e50572a9775a662410c5aff8300c8784Craig Stout        if (view != null) {
4890d841b3454f896da58deb506ca22730bfd04f34fDake Gu            if (rowViewHolder.mSelected) {
4903173fdc69a928880a271036570c235f874b86f65butterfield@google.com                ItemBridgeAdapter.ViewHolder ibh = (ItemBridgeAdapter.ViewHolder)
4913173fdc69a928880a271036570c235f874b86f65butterfield@google.com                        rowViewHolder.mGridView.getChildViewHolder(view);
4923173fdc69a928880a271036570c235f874b86f65butterfield@google.com
4933173fdc69a928880a271036570c235f874b86f65butterfield@google.com                if (mHoverCardPresenterSelector != null) {
4943a5038bd0fefa5628a31a21422bf2126c53472a9Craig Stout                    rowViewHolder.mHoverCardViewSwitcher.select(
4953a5038bd0fefa5628a31a21422bf2126c53472a9Craig Stout                            rowViewHolder.mGridView, view, ibh.mItem);
4963173fdc69a928880a271036570c235f874b86f65butterfield@google.com                }
4970246318f27a905a31df5a8af445cfe67d31dfb68Dake Gu                if (fireEvent && rowViewHolder.getOnItemViewSelectedListener() != null) {
4983a5038bd0fefa5628a31a21422bf2126c53472a9Craig Stout                    rowViewHolder.getOnItemViewSelectedListener().onItemSelected(
4993a5038bd0fefa5628a31a21422bf2126c53472a9Craig Stout                            ibh.mHolder, ibh.mItem, rowViewHolder, rowViewHolder.mRow);
5003173fdc69a928880a271036570c235f874b86f65butterfield@google.com                }
5013173fdc69a928880a271036570c235f874b86f65butterfield@google.com            }
5023173fdc69a928880a271036570c235f874b86f65butterfield@google.com        } else {
50347520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (mHoverCardPresenterSelector != null) {
50447520b68e50572a9775a662410c5aff8300c8784Craig Stout                rowViewHolder.mHoverCardViewSwitcher.unselect();
50547520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
5060246318f27a905a31df5a8af445cfe67d31dfb68Dake Gu            if (fireEvent && rowViewHolder.getOnItemViewSelectedListener() != null) {
5073a5038bd0fefa5628a31a21422bf2126c53472a9Craig Stout                rowViewHolder.getOnItemViewSelectedListener().onItemSelected(
5083a5038bd0fefa5628a31a21422bf2126c53472a9Craig Stout                        null, null, rowViewHolder, rowViewHolder.mRow);
5099de363b8db05106b03d115c266859fe200d41db7Dake Gu            }
51047520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
51147520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
51247520b68e50572a9775a662410c5aff8300c8784Craig Stout
5134cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    private static void initStatics(Context context) {
5144cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        if (sSelectedRowTopPadding == 0) {
5154cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            sSelectedRowTopPadding = context.getResources().getDimensionPixelSize(
5164cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout                    R.dimen.lb_browse_selected_row_top_padding);
5174cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            sExpandedSelectedRowTopPadding = context.getResources().getDimensionPixelSize(
5184cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout                    R.dimen.lb_browse_expanded_selected_row_top_padding);
5194cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            sExpandedRowNoHovercardBottomPadding = context.getResources().getDimensionPixelSize(
5204cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout                    R.dimen.lb_browse_expanded_row_no_hovercard_bottom_padding);
5214cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        }
5224cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    }
5234cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout
5244cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    private int getSpaceUnderBaseline(ListRowPresenter.ViewHolder vh) {
5254cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        RowHeaderPresenter.ViewHolder headerViewHolder = vh.getHeaderViewHolder();
5264cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        if (headerViewHolder != null) {
5274cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            if (getHeaderPresenter() != null) {
5284cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout                return getHeaderPresenter().getSpaceUnderBaseline(headerViewHolder);
5294cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            }
5304cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            return headerViewHolder.view.getPaddingBottom();
5314cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        }
5324cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        return 0;
5334cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    }
5344cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout
5354cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    private void setVerticalPadding(ListRowPresenter.ViewHolder vh) {
5364cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        int paddingTop, paddingBottom;
5373146269a82645438b55a41c679047e3be36e65dfCraig Stout        // Note: sufficient bottom padding needed for card shadows.
5384cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        if (vh.isExpanded()) {
5394cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            int headerSpaceUnderBaseline = getSpaceUnderBaseline(vh);
5404cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            if (DEBUG) Log.v(TAG, "headerSpaceUnderBaseline " + headerSpaceUnderBaseline);
5414cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            paddingTop = (vh.isSelected() ? sExpandedSelectedRowTopPadding : vh.mPaddingTop) -
5424cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout                    headerSpaceUnderBaseline;
5434cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            paddingBottom = mHoverCardPresenterSelector == null ?
5444cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout                    sExpandedRowNoHovercardBottomPadding : vh.mPaddingBottom;
5454cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        } else if (vh.isSelected()) {
5463146269a82645438b55a41c679047e3be36e65dfCraig Stout            paddingTop = sSelectedRowTopPadding - vh.mPaddingBottom;
5473146269a82645438b55a41c679047e3be36e65dfCraig Stout            paddingBottom = sSelectedRowTopPadding;
5484cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        } else {
5493146269a82645438b55a41c679047e3be36e65dfCraig Stout            paddingTop = 0;
5503146269a82645438b55a41c679047e3be36e65dfCraig Stout            paddingBottom = vh.mPaddingBottom;
5514cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        }
5524cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        vh.getGridView().setPadding(vh.mPaddingLeft, paddingTop, vh.mPaddingRight,
5534cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout                paddingBottom);
5544cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    }
5554cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout
55647520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
55747520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) {
5584cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        initStatics(parent.getContext());
559cb13a318e577e14461eb008071dddf762847de42Dake Gu        ListRowView rowView = new ListRowView(parent.getContext());
5609240e796bc63422c28f2707840bd99c48573279bDake Gu        setupFadingEffect(rowView);
561f272f7533fcb5aba341e9ab2f4ff0421d668a8caCraig Stout        if (mRowHeight != 0) {
562a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn            rowView.getGridView().setRowHeight(mRowHeight);
563a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        }
56447520b68e50572a9775a662410c5aff8300c8784Craig Stout        return new ViewHolder(rowView, rowView.getGridView(), this);
56547520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
56647520b68e50572a9775a662410c5aff8300c8784Craig Stout
567cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield    /**
568cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield     * Dispatch item selected event using current selected item in the {@link HorizontalGridView}.
569cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield     * The method should only be called from onRowViewSelected().
570cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield     */
571cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield    @Override
572cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield    protected void dispatchItemSelectedListener(RowPresenter.ViewHolder holder, boolean selected) {
573cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield        ViewHolder vh = (ViewHolder)holder;
574cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield        ItemBridgeAdapter.ViewHolder itemViewHolder = (ItemBridgeAdapter.ViewHolder)
575cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield                vh.mGridView.findViewHolderForPosition(vh.mGridView.getSelectedPosition());
576cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield        if (itemViewHolder == null) {
577cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield            super.dispatchItemSelectedListener(holder, selected);
578cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield            return;
579cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield        }
580cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield
581cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield        if (selected) {
5823a5038bd0fefa5628a31a21422bf2126c53472a9Craig Stout            if (holder.getOnItemViewSelectedListener() != null) {
5833a5038bd0fefa5628a31a21422bf2126c53472a9Craig Stout                holder.getOnItemViewSelectedListener().onItemSelected(
584cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield                        itemViewHolder.getViewHolder(), itemViewHolder.mItem, vh, vh.getRow());
585cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield            }
586cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield        }
587cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield    }
588cb04695965b44b6ff633a773426df286d3bfaad9John Butterfield
58947520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
59047520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected void onRowViewSelected(RowPresenter.ViewHolder holder, boolean selected) {
5912f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        super.onRowViewSelected(holder, selected);
5924cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        ViewHolder vh = (ViewHolder) holder;
5934cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        setVerticalPadding(vh);
5944cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        updateFooterViewSwitcher(vh);
59547520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
59647520b68e50572a9775a662410c5aff8300c8784Craig Stout
59747520b68e50572a9775a662410c5aff8300c8784Craig Stout    /*
59847520b68e50572a9775a662410c5aff8300c8784Craig Stout     * Show or hide hover card when row selection or expanded state is changed.
59947520b68e50572a9775a662410c5aff8300c8784Craig Stout     */
60047520b68e50572a9775a662410c5aff8300c8784Craig Stout    private void updateFooterViewSwitcher(ViewHolder vh) {
60147520b68e50572a9775a662410c5aff8300c8784Craig Stout        if (vh.mExpanded && vh.mSelected) {
60247520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (mHoverCardPresenterSelector != null) {
60347520b68e50572a9775a662410c5aff8300c8784Craig Stout                vh.mHoverCardViewSwitcher.init((ViewGroup) vh.view,
60447520b68e50572a9775a662410c5aff8300c8784Craig Stout                        mHoverCardPresenterSelector);
60547520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
60602e411c2c69d20aab138f1a162a24ea650eff7a1Dake Gu            ItemBridgeAdapter.ViewHolder ibh = (ItemBridgeAdapter.ViewHolder)
60702e411c2c69d20aab138f1a162a24ea650eff7a1Dake Gu                    vh.mGridView.findViewHolderForPosition(
60802e411c2c69d20aab138f1a162a24ea650eff7a1Dake Gu                            vh.mGridView.getSelectedPosition());
6090246318f27a905a31df5a8af445cfe67d31dfb68Dake Gu            selectChildView(vh, ibh == null ? null : ibh.itemView, false);
61047520b68e50572a9775a662410c5aff8300c8784Craig Stout        } else {
61147520b68e50572a9775a662410c5aff8300c8784Craig Stout            if (mHoverCardPresenterSelector != null) {
6122f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu                vh.mHoverCardViewSwitcher.unselect();
61347520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
61447520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
61547520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
61647520b68e50572a9775a662410c5aff8300c8784Craig Stout
6179240e796bc63422c28f2707840bd99c48573279bDake Gu    private void setupFadingEffect(ListRowView rowView) {
6189240e796bc63422c28f2707840bd99c48573279bDake Gu        // content is completely faded at 1/2 padding of left, fading length is 1/2 of padding.
6199240e796bc63422c28f2707840bd99c48573279bDake Gu        HorizontalGridView gridView = rowView.getGridView();
6209240e796bc63422c28f2707840bd99c48573279bDake Gu        if (mBrowseRowsFadingEdgeLength < 0) {
6219240e796bc63422c28f2707840bd99c48573279bDake Gu            TypedArray ta = gridView.getContext()
6229240e796bc63422c28f2707840bd99c48573279bDake Gu                    .obtainStyledAttributes(R.styleable.LeanbackTheme);
6239240e796bc63422c28f2707840bd99c48573279bDake Gu            mBrowseRowsFadingEdgeLength = (int) ta.getDimension(
6249240e796bc63422c28f2707840bd99c48573279bDake Gu                    R.styleable.LeanbackTheme_browseRowsFadingEdgeLength, 0);
6259240e796bc63422c28f2707840bd99c48573279bDake Gu            ta.recycle();
62647520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
6279240e796bc63422c28f2707840bd99c48573279bDake Gu        gridView.setFadingLeftEdgeLength(mBrowseRowsFadingEdgeLength);
62847520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
62947520b68e50572a9775a662410c5aff8300c8784Craig Stout
63047520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
63147520b68e50572a9775a662410c5aff8300c8784Craig Stout    protected void onRowViewExpanded(RowPresenter.ViewHolder holder, boolean expanded) {
63247520b68e50572a9775a662410c5aff8300c8784Craig Stout        super.onRowViewExpanded(holder, expanded);
63347520b68e50572a9775a662410c5aff8300c8784Craig Stout        ViewHolder vh = (ViewHolder) holder;
634a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        if (getRowHeight() != getExpandedRowHeight()) {
635a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn            int newHeight = expanded ? getExpandedRowHeight() : getRowHeight();
636a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn            vh.getGridView().setRowHeight(newHeight);
637a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn        }
6384cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        setVerticalPadding(vh);
63947520b68e50572a9775a662410c5aff8300c8784Craig Stout        updateFooterViewSwitcher(vh);
64047520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
64147520b68e50572a9775a662410c5aff8300c8784Craig Stout
64247520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
643cb13a318e577e14461eb008071dddf762847de42Dake Gu    protected void onBindRowViewHolder(RowPresenter.ViewHolder holder, Object item) {
644cb13a318e577e14461eb008071dddf762847de42Dake Gu        super.onBindRowViewHolder(holder, item);
645cb13a318e577e14461eb008071dddf762847de42Dake Gu        ViewHolder vh = (ViewHolder) holder;
64647520b68e50572a9775a662410c5aff8300c8784Craig Stout        ListRow rowItem = (ListRow) item;
64747520b68e50572a9775a662410c5aff8300c8784Craig Stout        vh.mItemBridgeAdapter.setAdapter(rowItem.getAdapter());
64847520b68e50572a9775a662410c5aff8300c8784Craig Stout        vh.mGridView.setAdapter(vh.mItemBridgeAdapter);
649ac30644710e427c77b9d1f20ae385590bdac6c60Dake Gu        vh.mGridView.setContentDescription(rowItem.getContentDescription());
65047520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
65147520b68e50572a9775a662410c5aff8300c8784Craig Stout
65247520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
653cb13a318e577e14461eb008071dddf762847de42Dake Gu    protected void onUnbindRowViewHolder(RowPresenter.ViewHolder holder) {
6545358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout        ViewHolder vh = (ViewHolder) holder;
6555358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout        vh.mGridView.setAdapter(null);
6565358b0ca6ed795892bd097fdf15d41fb6b1a03d2Craig Stout        vh.mItemBridgeAdapter.clear();
657cb13a318e577e14461eb008071dddf762847de42Dake Gu        super.onUnbindRowViewHolder(holder);
65847520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
65947520b68e50572a9775a662410c5aff8300c8784Craig Stout
660cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    /**
661cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * ListRowPresenter overrides the default select effect of {@link RowPresenter}
662cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * and return false.
663cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     */
664cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    @Override
665cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    public final boolean isUsingDefaultSelectEffect() {
666cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        return false;
667cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
668cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
669cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    /**
670cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * Returns true so that default select effect is applied to each individual
671cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * child of {@link HorizontalGridView}.  Subclass may return false to disable
672cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * the default implementation.
673cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * @see #onSelectLevelChanged(RowPresenter.ViewHolder)
674cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     */
675cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    public boolean isUsingDefaultListSelectEffect() {
676cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        return true;
677cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
678cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
679cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    /**
680dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu     * Returns true if SDK >= 18, where default shadow
681892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * is applied to each individual child of {@link HorizontalGridView}.
682892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * Subclass may return false to disable.
683892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     */
684892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    public boolean isUsingDefaultShadow() {
685254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu        return ShadowOverlayHelper.supportsShadow();
686892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
687892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
688892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    /**
6890fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu     * Returns true if SDK >= L, where Z shadow is enabled so that Z order is enabled
6900fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu     * on each child of horizontal list.   If subclass returns false in isUsingDefaultShadow()
6910fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu     * and does not use Z-shadow on SDK >= L, it should override isUsingZOrder() return false.
6920fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu     */
693f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    public boolean isUsingZOrder(Context context) {
694254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu        return !Settings.getInstance(context).preferStaticShadows();
6950fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu    }
6960fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu
6970fcad32410ad29031630bb9cc2da35d33a4aa906Dake Gu    /**
698a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Enables or disables child shadow.
699892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * This is not only for enable/disable default shadow implementation but also subclass must
700892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * respect this flag.
701892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     */
702892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    public final void setShadowEnabled(boolean enabled) {
703892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        mShadowEnabled = enabled;
704892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
705892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
706892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    /**
707892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * Returns true if child shadow is enabled.
708892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * This is not only for enable/disable default shadow implementation but also subclass must
709892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     * respect this flag.
710892181367d658f347d00ea5e091aa31f086b2a20Dake Gu     */
711892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    public final boolean getShadowEnabled() {
712892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        return mShadowEnabled;
713892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
714892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
7154f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout    /**
7164f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout     * Enables or disabled rounded corners on children of this row.
7174f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout     * Supported on Android SDK >= L.
7184f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout     */
7194f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout    public final void enableChildRoundedCorners(boolean enable) {
7204f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout        mRoundedCornersEnabled = enable;
7214f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout    }
7224f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout
7234f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout    /**
7244f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout     * Returns true if rounded corners are enabled for children of this row.
7254f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout     */
7264f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout    public final boolean areChildRoundedCornersEnabled() {
7274f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout        return mRoundedCornersEnabled;
7284f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout    }
7294f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout
730892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    final boolean needsDefaultShadow() {
731892181367d658f347d00ea5e091aa31f086b2a20Dake Gu        return isUsingDefaultShadow() && getShadowEnabled();
732892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
733892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
73485833087b2288e0f002de6b4ebcbc0564839a217Dake Gu    /**
73585833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     * When ListRowPresenter applies overlay color on the child,  it may change child's foreground
73685833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     * Drawable.  If application uses child's foreground for other purposes such as ripple effect,
73785833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     * it needs tell ListRowPresenter to keep the child's foreground.  The default value is true.
73885833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     *
73985833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     * @param keep true if keep foreground of child of this row, false ListRowPresenter might change
74085833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     *             the foreground of the child.
74185833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     */
74285833087b2288e0f002de6b4ebcbc0564839a217Dake Gu    public final void setKeepChildForeground(boolean keep) {
74385833087b2288e0f002de6b4ebcbc0564839a217Dake Gu        mKeepChildForeground = keep;
74485833087b2288e0f002de6b4ebcbc0564839a217Dake Gu    }
74585833087b2288e0f002de6b4ebcbc0564839a217Dake Gu
74685833087b2288e0f002de6b4ebcbc0564839a217Dake Gu    /**
747ce4c2014042fe6e4723bab30741039848adcf4beDake Gu     * Returns true if keeps foreground of child of this row, false otherwise.  When
748ce4c2014042fe6e4723bab30741039848adcf4beDake Gu     * ListRowPresenter applies overlay color on the child,  it may change child's foreground
749ce4c2014042fe6e4723bab30741039848adcf4beDake Gu     * Drawable.  If application uses child's foreground for other purposes such as ripple effect,
750ce4c2014042fe6e4723bab30741039848adcf4beDake Gu     * it needs tell ListRowPresenter to keep the child's foreground.  The default value is true.
75185833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     *
75285833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     * @return true if keeps foreground of child of this row, false otherwise.
75385833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     */
75485833087b2288e0f002de6b4ebcbc0564839a217Dake Gu    public final boolean isKeepChildForeground() {
75585833087b2288e0f002de6b4ebcbc0564839a217Dake Gu        return mKeepChildForeground;
75685833087b2288e0f002de6b4ebcbc0564839a217Dake Gu    }
75785833087b2288e0f002de6b4ebcbc0564839a217Dake Gu
75885833087b2288e0f002de6b4ebcbc0564839a217Dake Gu    /**
75985833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     * Create ShadowOverlayHelper Options.  Subclass may override.
76085833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     * e.g.
76185833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     * <code>
76285833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     * return new ShadowOverlayHelper.Options().roundedCornerRadius(10);
76385833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     * </code>
76485833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     *
76585833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     * @return The options to be used for shadow, overlay and rouded corner.
76685833087b2288e0f002de6b4ebcbc0564839a217Dake Gu     */
76785833087b2288e0f002de6b4ebcbc0564839a217Dake Gu    protected ShadowOverlayHelper.Options createShadowOverlayOptions() {
76885833087b2288e0f002de6b4ebcbc0564839a217Dake Gu        return ShadowOverlayHelper.Options.DEFAULT;
769892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    }
770892181367d658f347d00ea5e091aa31f086b2a20Dake Gu
771892181367d658f347d00ea5e091aa31f086b2a20Dake Gu    /**
772cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * Applies select level to header and draw a default color dim over each child
773cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * of {@link HorizontalGridView}.
774cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * <p>
775cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * Subclass may override this method.  A subclass
776cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * needs to call super.onSelectLevelChanged() for applying header select level
777cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * and optionally applying a default select level to each child view of
778cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * {@link HorizontalGridView} if {@link #isUsingDefaultListSelectEffect()}
779cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * is true.  Subclass may override {@link #isUsingDefaultListSelectEffect()} to return
780cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * false and deal with the individual item select level by itself.
781cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     * </p>
782cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu     */
783cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    @Override
784cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    protected void onSelectLevelChanged(RowPresenter.ViewHolder holder) {
785cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        super.onSelectLevelChanged(holder);
786254b417129de2a8c5612826a152f8a26c8f1d0e8Dake Gu        if (mShadowOverlayHelper != null && mShadowOverlayHelper.needsOverlay()) {
787cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu            ViewHolder vh = (ViewHolder) holder;
788892181367d658f347d00ea5e091aa31f086b2a20Dake Gu            int dimmedColor = vh.mColorDimmer.getPaint().getColor();
78985833087b2288e0f002de6b4ebcbc0564839a217Dake Gu            for (int i = 0, count = vh.mGridView.getChildCount(); i < count; i++) {
79085833087b2288e0f002de6b4ebcbc0564839a217Dake Gu                mShadowOverlayHelper.setOverlayColor(vh.mGridView.getChildAt(i), dimmedColor);
791cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu            }
7929240e796bc63422c28f2707840bd99c48573279bDake Gu            if (vh.mGridView.getFadingLeftEdge()) {
7939240e796bc63422c28f2707840bd99c48573279bDake Gu                vh.mGridView.invalidate();
7949240e796bc63422c28f2707840bd99c48573279bDake Gu            }
795cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        }
796cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
797cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
798709bb7083a089e788d84ffa81f2c4f60a1bc8cf2Dake Gu    @Override
799709bb7083a089e788d84ffa81f2c4f60a1bc8cf2Dake Gu    public void freeze(RowPresenter.ViewHolder holder, boolean freeze) {
800709bb7083a089e788d84ffa81f2c4f60a1bc8cf2Dake Gu        ViewHolder vh = (ViewHolder) holder;
801709bb7083a089e788d84ffa81f2c4f60a1bc8cf2Dake Gu        vh.mGridView.setScrollEnabled(!freeze);
802709bb7083a089e788d84ffa81f2c4f60a1bc8cf2Dake Gu    }
803709bb7083a089e788d84ffa81f2c4f60a1bc8cf2Dake Gu
804c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    @Override
8053f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu    public void setEntranceTransitionState(RowPresenter.ViewHolder holder,
8063f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu            boolean afterEntrance) {
8073f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu        super.setEntranceTransitionState(holder, afterEntrance);
808c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu        ((ViewHolder) holder).mGridView.setChildrenVisibility(
8093f0f3eb255bde49549a77c0b5d252decaa2a0202Dake Gu                afterEntrance? View.VISIBLE : View.INVISIBLE);
810c04ca1b14c5bf9ecac80fc53d3f28a5a7fdd4e77Dake Gu    }
81147520b68e50572a9775a662410c5aff8300c8784Craig Stout}
812