1a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn/*
2a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn * Copyright (C) 2014 The Android Open Source Project
3a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn *
4a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn * in compliance with the License. You may obtain a copy of the License at
6a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn *
7a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn * http://www.apache.org/licenses/LICENSE-2.0
8a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn *
9a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn * Unless required by applicable law or agreed to in writing, software distributed under the License
10a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn * or implied. See the License for the specific language governing permissions and limitations under
12a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn * the License.
13a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn */
14ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.leanback.widget;
15a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
164121f22713bbed467a977ec0d867ef53989ff374Dake Guimport android.app.Activity;
17d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stoutimport android.content.Context;
18d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stoutimport android.graphics.Color;
1909d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stoutimport android.graphics.drawable.ColorDrawable;
203103f63e99d47573823957f7aa34308555873221Aurimas Liutikasimport android.graphics.drawable.Drawable;
21d825ff3727407a154a35e20b3a9adc79e57879b9Dake Guimport android.os.Handler;
222e0c922430f8c285b4325da52d69c09451069c93Craig Stoutimport android.util.Log;
23d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stoutimport android.util.TypedValue;
2460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stoutimport android.view.KeyEvent;
25a83005b70853ea52c5d98910762344de16b850a8Tim Kilbournimport android.view.LayoutInflater;
26a83005b70853ea52c5d98910762344de16b850a8Tim Kilbournimport android.view.View;
27a83005b70853ea52c5d98910762344de16b850a8Tim Kilbournimport android.view.ViewGroup;
28a83005b70853ea52c5d98910762344de16b850a8Tim Kilbournimport android.widget.FrameLayout;
29a83005b70853ea52c5d98910762344de16b850a8Tim Kilbournimport android.widget.ImageView;
30a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
318619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.annotation.ColorInt;
328619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.leanback.R;
338619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.recyclerview.widget.RecyclerView;
348619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikas
35a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn/**
36a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Renders a {@link DetailsOverviewRow} to display an overview of an item.
37a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Typically this row will be the first row in a fragment
38ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * such as the {@link androidx.leanback.app.DetailsFragment
39a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * DetailsFragment}.  The View created by the DetailsOverviewRowPresenter is made in three parts:
4018c8048f17940359b8bce99cb46d24337bff8997Dake Gu * ImageView on the left, action list view on the bottom and a customizable detailed
4118c8048f17940359b8bce99cb46d24337bff8997Dake Gu * description view on the right.
42a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn *
4318c8048f17940359b8bce99cb46d24337bff8997Dake Gu * <p>The detailed description is rendered using a {@link Presenter} passed in
44a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * {@link #DetailsOverviewRowPresenter(Presenter)}.  Typically this will be an instance of
45a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * {@link AbstractDetailsDescriptionPresenter}.  The application can access the
46a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * detailed description ViewHolder from {@link ViewHolder#mDetailsDescriptionViewHolder}.
4718c8048f17940359b8bce99cb46d24337bff8997Dake Gu * </p>
4818c8048f17940359b8bce99cb46d24337bff8997Dake Gu *
4918c8048f17940359b8bce99cb46d24337bff8997Dake Gu * <p>
5018c8048f17940359b8bce99cb46d24337bff8997Dake Gu * To participate in activity transition, call {@link #setSharedElementEnterTransition(Activity,
5118c8048f17940359b8bce99cb46d24337bff8997Dake Gu * String)} during Activity's onCreate().
5218c8048f17940359b8bce99cb46d24337bff8997Dake Gu * </p>
5318c8048f17940359b8bce99cb46d24337bff8997Dake Gu *
5418c8048f17940359b8bce99cb46d24337bff8997Dake Gu * <p>
5518c8048f17940359b8bce99cb46d24337bff8997Dake Gu * Because transition support and layout are fully controlled by DetailsOverviewRowPresenter,
5618c8048f17940359b8bce99cb46d24337bff8997Dake Gu * developer can not override DetailsOverviewRowPresenter.ViewHolder for adding/replacing views
57a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * of DetailsOverviewRowPresenter.  If further customization is required beyond replacing
58a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * the detailed description, the application should create a new row presenter class.
5918c8048f17940359b8bce99cb46d24337bff8997Dake Gu * </p>
600246318f27a905a31df5a8af445cfe67d31dfb68Dake Gu * @deprecated  Use {@link FullWidthDetailsOverviewRowPresenter}
61a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn */
620246318f27a905a31df5a8af445cfe67d31dfb68Dake Gu@Deprecated
63a83005b70853ea52c5d98910762344de16b850a8Tim Kilbournpublic class DetailsOverviewRowPresenter extends RowPresenter {
64a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
6560e00f895b6f4dd25f181f377adf98e0715be4b6Dake Gu    static final String TAG = "DetailsOverviewRowP";
6699ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    static final boolean DEBUG = false;
67a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
682e0c922430f8c285b4325da52d69c09451069c93Craig Stout    private static final int MORE_ACTIONS_FADE_MS = 100;
69d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu    private static final long DEFAULT_TIMEOUT = 5000;
702e0c922430f8c285b4325da52d69c09451069c93Craig Stout
7171fddded48048acfa744ac352166770c91a1c2b1Dake Gu    class ActionsItemBridgeAdapter extends ItemBridgeAdapter {
7271fddded48048acfa744ac352166770c91a1c2b1Dake Gu        DetailsOverviewRowPresenter.ViewHolder mViewHolder;
7371fddded48048acfa744ac352166770c91a1c2b1Dake Gu
7471fddded48048acfa744ac352166770c91a1c2b1Dake Gu        ActionsItemBridgeAdapter(DetailsOverviewRowPresenter.ViewHolder viewHolder) {
7571fddded48048acfa744ac352166770c91a1c2b1Dake Gu            mViewHolder = viewHolder;
7671fddded48048acfa744ac352166770c91a1c2b1Dake Gu        }
7771fddded48048acfa744ac352166770c91a1c2b1Dake Gu
7871fddded48048acfa744ac352166770c91a1c2b1Dake Gu        @Override
7971fddded48048acfa744ac352166770c91a1c2b1Dake Gu        public void onBind(final ItemBridgeAdapter.ViewHolder ibvh) {
803103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            if (mViewHolder.getOnItemViewClickedListener() != null
813103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                    || mActionClickedListener != null) {
8271fddded48048acfa744ac352166770c91a1c2b1Dake Gu                ibvh.getPresenter().setOnClickListener(
8371fddded48048acfa744ac352166770c91a1c2b1Dake Gu                        ibvh.getViewHolder(), new View.OnClickListener() {
8471fddded48048acfa744ac352166770c91a1c2b1Dake Gu                            @Override
8571fddded48048acfa744ac352166770c91a1c2b1Dake Gu                            public void onClick(View v) {
863a5038bd0fefa5628a31a21422bf2126c53472a9Craig Stout                                if (mViewHolder.getOnItemViewClickedListener() != null) {
873a5038bd0fefa5628a31a21422bf2126c53472a9Craig Stout                                    mViewHolder.getOnItemViewClickedListener().onItemClicked(
8871fddded48048acfa744ac352166770c91a1c2b1Dake Gu                                            ibvh.getViewHolder(), ibvh.getItem(),
8971fddded48048acfa744ac352166770c91a1c2b1Dake Gu                                            mViewHolder, mViewHolder.getRow());
9071fddded48048acfa744ac352166770c91a1c2b1Dake Gu                                }
9171fddded48048acfa744ac352166770c91a1c2b1Dake Gu                                if (mActionClickedListener != null) {
9271fddded48048acfa744ac352166770c91a1c2b1Dake Gu                                    mActionClickedListener.onActionClicked((Action) ibvh.getItem());
9371fddded48048acfa744ac352166770c91a1c2b1Dake Gu                                }
9471fddded48048acfa744ac352166770c91a1c2b1Dake Gu                            }
9571fddded48048acfa744ac352166770c91a1c2b1Dake Gu                        });
9671fddded48048acfa744ac352166770c91a1c2b1Dake Gu            }
9771fddded48048acfa744ac352166770c91a1c2b1Dake Gu        }
9871fddded48048acfa744ac352166770c91a1c2b1Dake Gu        @Override
9971fddded48048acfa744ac352166770c91a1c2b1Dake Gu        public void onUnbind(final ItemBridgeAdapter.ViewHolder ibvh) {
1003103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            if (mViewHolder.getOnItemViewClickedListener() != null
1013103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                    || mActionClickedListener != null) {
10271fddded48048acfa744ac352166770c91a1c2b1Dake Gu                ibvh.getPresenter().setOnClickListener(ibvh.getViewHolder(), null);
10371fddded48048acfa744ac352166770c91a1c2b1Dake Gu            }
10471fddded48048acfa744ac352166770c91a1c2b1Dake Gu        }
10571fddded48048acfa744ac352166770c91a1c2b1Dake Gu        @Override
10671fddded48048acfa744ac352166770c91a1c2b1Dake Gu        public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) {
10771fddded48048acfa744ac352166770c91a1c2b1Dake Gu            // Remove first to ensure we don't add ourselves more than once.
10871fddded48048acfa744ac352166770c91a1c2b1Dake Gu            viewHolder.itemView.removeOnLayoutChangeListener(mViewHolder.mLayoutChangeListener);
10971fddded48048acfa744ac352166770c91a1c2b1Dake Gu            viewHolder.itemView.addOnLayoutChangeListener(mViewHolder.mLayoutChangeListener);
11071fddded48048acfa744ac352166770c91a1c2b1Dake Gu        }
11171fddded48048acfa744ac352166770c91a1c2b1Dake Gu        @Override
11271fddded48048acfa744ac352166770c91a1c2b1Dake Gu        public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder viewHolder) {
11371fddded48048acfa744ac352166770c91a1c2b1Dake Gu            viewHolder.itemView.removeOnLayoutChangeListener(mViewHolder.mLayoutChangeListener);
11471fddded48048acfa744ac352166770c91a1c2b1Dake Gu            mViewHolder.checkFirstAndLastPosition(false);
11571fddded48048acfa744ac352166770c91a1c2b1Dake Gu        }
11671fddded48048acfa744ac352166770c91a1c2b1Dake Gu    }
11771fddded48048acfa744ac352166770c91a1c2b1Dake Gu
11880d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn    /**
11980d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn     * A ViewHolder for the DetailsOverviewRow.
12080d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn     */
121cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout    public final class ViewHolder extends RowPresenter.ViewHolder {
12209d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout        final FrameLayout mOverviewFrame;
123b34a2372153298ebdc3e148e1c1f3b3924efab08Dake Gu        final ViewGroup mOverviewView;
124a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        final ImageView mImageView;
1254121f22713bbed467a977ec0d867ef53989ff374Dake Gu        final ViewGroup mRightPanel;
126a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        final FrameLayout mDetailsDescriptionFrame;
127a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        final HorizontalGridView mActionsRow;
12818c8048f17940359b8bce99cb46d24337bff8997Dake Gu        public final Presenter.ViewHolder mDetailsDescriptionViewHolder;
12983118b72d02074ee35f07ad0253579565c16882bCraig Stout        int mNumItems;
13083118b72d02074ee35f07ad0253579565c16882bCraig Stout        boolean mShowMoreRight;
13183118b72d02074ee35f07ad0253579565c16882bCraig Stout        boolean mShowMoreLeft;
13271fddded48048acfa744ac352166770c91a1c2b1Dake Gu        ItemBridgeAdapter mActionBridgeAdapter;
133d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        final Handler mHandler = new Handler();
134a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
135d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        final Runnable mUpdateDrawableCallback = new Runnable() {
136d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu            @Override
137d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu            public void run() {
138d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu                bindImageDrawable(ViewHolder.this);
139d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu            }
140d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        };
141d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu
142d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        final DetailsOverviewRow.Listener mListener = new DetailsOverviewRow.Listener() {
143d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu            @Override
144d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu            public void onImageDrawableChanged(DetailsOverviewRow row) {
145d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu                mHandler.removeCallbacks(mUpdateDrawableCallback);
146d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu                mHandler.post(mUpdateDrawableCallback);
147d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu            }
148d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu
149d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu            @Override
150d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu            public void onItemChanged(DetailsOverviewRow row) {
151d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu                if (mDetailsDescriptionViewHolder != null) {
152d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu                    mDetailsPresenter.onUnbindViewHolder(mDetailsDescriptionViewHolder);
153d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu                }
154d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu                mDetailsPresenter.onBindViewHolder(mDetailsDescriptionViewHolder, row.getItem());
155d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu            }
156d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu
157d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu            @Override
158d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu            public void onActionsAdapterChanged(DetailsOverviewRow row) {
159d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu                bindActions(row.getActionsAdapter());
160d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu            }
161d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        };
162d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu
163d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        void bindActions(ObjectAdapter adapter) {
164cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout            mActionBridgeAdapter.setAdapter(adapter);
16537eb0e53ba5363bbe15314c7d19d4b2d6024a5aaDake Gu            mActionsRow.setAdapter(mActionBridgeAdapter);
166cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout            mNumItems = mActionBridgeAdapter.getItemCount();
1672e0c922430f8c285b4325da52d69c09451069c93Craig Stout
16883118b72d02074ee35f07ad0253579565c16882bCraig Stout            mShowMoreRight = false;
16983118b72d02074ee35f07ad0253579565c16882bCraig Stout            mShowMoreLeft = true;
17083118b72d02074ee35f07ad0253579565c16882bCraig Stout            showMoreLeft(false);
17183118b72d02074ee35f07ad0253579565c16882bCraig Stout        }
17283118b72d02074ee35f07ad0253579565c16882bCraig Stout
173819b4e55bcf37847548a55c5dac0dfa8323975f6Craig Stout        final View.OnLayoutChangeListener mLayoutChangeListener =
174819b4e55bcf37847548a55c5dac0dfa8323975f6Craig Stout                new View.OnLayoutChangeListener() {
175819b4e55bcf37847548a55c5dac0dfa8323975f6Craig Stout
176819b4e55bcf37847548a55c5dac0dfa8323975f6Craig Stout            @Override
177819b4e55bcf37847548a55c5dac0dfa8323975f6Craig Stout            public void onLayoutChange(View v, int left, int top, int right,
178819b4e55bcf37847548a55c5dac0dfa8323975f6Craig Stout                    int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
179819b4e55bcf37847548a55c5dac0dfa8323975f6Craig Stout                if (DEBUG) Log.v(TAG, "onLayoutChange " + v);
180819b4e55bcf37847548a55c5dac0dfa8323975f6Craig Stout                checkFirstAndLastPosition(false);
181819b4e55bcf37847548a55c5dac0dfa8323975f6Craig Stout            }
182819b4e55bcf37847548a55c5dac0dfa8323975f6Craig Stout        };
183819b4e55bcf37847548a55c5dac0dfa8323975f6Craig Stout
184cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout        final OnChildSelectedListener mChildSelectedListener = new OnChildSelectedListener() {
185cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout            @Override
186cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
187cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout                dispatchItemSelection(view);
188cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout            }
189cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout        };
190cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout
191cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout        void dispatchItemSelection(View view) {
192cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout            if (!isSelected()) {
193cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout                return;
194cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout            }
1953103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            ItemBridgeAdapter.ViewHolder ibvh = (ItemBridgeAdapter.ViewHolder) (view != null
1963103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                    ? mActionsRow.getChildViewHolder(view)
1973103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                    : mActionsRow.findViewHolderForPosition(mActionsRow.getSelectedPosition()));
198cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout            if (ibvh == null) {
199cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout                if (getOnItemViewSelectedListener() != null) {
200cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout                    getOnItemViewSelectedListener().onItemSelected(null, null,
201cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout                            ViewHolder.this, getRow());
202cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout                }
203cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout            } else {
204cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout                if (getOnItemViewSelectedListener() != null) {
205cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout                    getOnItemViewSelectedListener().onItemSelected(ibvh.getViewHolder(), ibvh.getItem(),
206cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout                            ViewHolder.this, getRow());
207cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout                }
208cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout            }
209cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout        };
210cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout
21183118b72d02074ee35f07ad0253579565c16882bCraig Stout        final RecyclerView.OnScrollListener mScrollListener =
21283118b72d02074ee35f07ad0253579565c16882bCraig Stout                new RecyclerView.OnScrollListener() {
2132e0c922430f8c285b4325da52d69c09451069c93Craig Stout
2142e0c922430f8c285b4325da52d69c09451069c93Craig Stout            @Override
215cef7b4942bacc862ea4eac66952e9f7aba027d18Yigit Boyar            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
2162e0c922430f8c285b4325da52d69c09451069c93Craig Stout            }
2172e0c922430f8c285b4325da52d69c09451069c93Craig Stout            @Override
218cef7b4942bacc862ea4eac66952e9f7aba027d18Yigit Boyar            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
21983118b72d02074ee35f07ad0253579565c16882bCraig Stout                checkFirstAndLastPosition(true);
2202e0c922430f8c285b4325da52d69c09451069c93Craig Stout            }
22183118b72d02074ee35f07ad0253579565c16882bCraig Stout        };
22283118b72d02074ee35f07ad0253579565c16882bCraig Stout
22383118b72d02074ee35f07ad0253579565c16882bCraig Stout        private int getViewCenter(View view) {
22483118b72d02074ee35f07ad0253579565c16882bCraig Stout            return (view.getRight() - view.getLeft()) / 2;
22583118b72d02074ee35f07ad0253579565c16882bCraig Stout        }
22683118b72d02074ee35f07ad0253579565c16882bCraig Stout
22799ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        void checkFirstAndLastPosition(boolean fromScroll) {
22883118b72d02074ee35f07ad0253579565c16882bCraig Stout            RecyclerView.ViewHolder viewHolder;
2292e0c922430f8c285b4325da52d69c09451069c93Craig Stout
23083118b72d02074ee35f07ad0253579565c16882bCraig Stout            viewHolder = mActionsRow.findViewHolderForPosition(mNumItems - 1);
2313103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            boolean showRight = (viewHolder == null
2323103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                    || viewHolder.itemView.getRight() > mActionsRow.getWidth());
23383118b72d02074ee35f07ad0253579565c16882bCraig Stout
23483118b72d02074ee35f07ad0253579565c16882bCraig Stout            viewHolder = mActionsRow.findViewHolderForPosition(0);
23583118b72d02074ee35f07ad0253579565c16882bCraig Stout            boolean showLeft = (viewHolder == null || viewHolder.itemView.getLeft() < 0);
23683118b72d02074ee35f07ad0253579565c16882bCraig Stout
2373103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            if (DEBUG) {
2383103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                Log.v(TAG, "checkFirstAndLast fromScroll " + fromScroll
2393103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                        + " showRight " + showRight + " showLeft " + showLeft);
2403103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            }
24183118b72d02074ee35f07ad0253579565c16882bCraig Stout
24283118b72d02074ee35f07ad0253579565c16882bCraig Stout            showMoreRight(showRight);
24383118b72d02074ee35f07ad0253579565c16882bCraig Stout            showMoreLeft(showLeft);
24483118b72d02074ee35f07ad0253579565c16882bCraig Stout        }
24583118b72d02074ee35f07ad0253579565c16882bCraig Stout
24683118b72d02074ee35f07ad0253579565c16882bCraig Stout        private void showMoreLeft(boolean show) {
24783118b72d02074ee35f07ad0253579565c16882bCraig Stout            if (show != mShowMoreLeft) {
24883118b72d02074ee35f07ad0253579565c16882bCraig Stout                mActionsRow.setFadingLeftEdge(show);
24983118b72d02074ee35f07ad0253579565c16882bCraig Stout                mShowMoreLeft = show;
2502e0c922430f8c285b4325da52d69c09451069c93Craig Stout            }
25183118b72d02074ee35f07ad0253579565c16882bCraig Stout        }
2522e0c922430f8c285b4325da52d69c09451069c93Craig Stout
25383118b72d02074ee35f07ad0253579565c16882bCraig Stout        private void showMoreRight(boolean show) {
25483118b72d02074ee35f07ad0253579565c16882bCraig Stout            if (show != mShowMoreRight) {
25583118b72d02074ee35f07ad0253579565c16882bCraig Stout                mActionsRow.setFadingRightEdge(show);
25683118b72d02074ee35f07ad0253579565c16882bCraig Stout                mShowMoreRight = show;
2572e0c922430f8c285b4325da52d69c09451069c93Craig Stout            }
2582e0c922430f8c285b4325da52d69c09451069c93Craig Stout        }
2592e0c922430f8c285b4325da52d69c09451069c93Craig Stout
26080d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn        /**
26180d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn         * Constructor for the ViewHolder.
26280d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn         *
26380d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn         * @param rootView The root View that this view holder will be attached
26480d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn         *        to.
26580d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn         */
26618c8048f17940359b8bce99cb46d24337bff8997Dake Gu        public ViewHolder(View rootView, Presenter detailsPresenter) {
267a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn            super(rootView);
26809d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout            mOverviewFrame = (FrameLayout) rootView.findViewById(R.id.details_frame);
269b34a2372153298ebdc3e148e1c1f3b3924efab08Dake Gu            mOverviewView = (ViewGroup) rootView.findViewById(R.id.details_overview);
270a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn            mImageView = (ImageView) rootView.findViewById(R.id.details_overview_image);
2714121f22713bbed467a977ec0d867ef53989ff374Dake Gu            mRightPanel = (ViewGroup) rootView.findViewById(R.id.details_overview_right_panel);
272a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn            mDetailsDescriptionFrame =
2734121f22713bbed467a977ec0d867ef53989ff374Dake Gu                    (FrameLayout) mRightPanel.findViewById(R.id.details_overview_description);
27470c858a5ca5b7ed9862e2edfa43912faecf42f96Tim Kilbourn            mActionsRow =
2754121f22713bbed467a977ec0d867ef53989ff374Dake Gu                    (HorizontalGridView) mRightPanel.findViewById(R.id.details_overview_actions);
276ceb7ab2ddd6e157cd4ade0f14a382c39428163c4Dake Gu            mActionsRow.setHasOverlappingRendering(false);
2772e0c922430f8c285b4325da52d69c09451069c93Craig Stout            mActionsRow.setOnScrollListener(mScrollListener);
278cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout            mActionsRow.setAdapter(mActionBridgeAdapter);
279cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout            mActionsRow.setOnChildSelectedListener(mChildSelectedListener);
2802e0c922430f8c285b4325da52d69c09451069c93Craig Stout
2812e0c922430f8c285b4325da52d69c09451069c93Craig Stout            final int fadeLength = rootView.getResources().getDimensionPixelSize(
2822e0c922430f8c285b4325da52d69c09451069c93Craig Stout                    R.dimen.lb_details_overview_actions_fade_size);
2832e0c922430f8c285b4325da52d69c09451069c93Craig Stout            mActionsRow.setFadingRightEdgeLength(fadeLength);
2842e0c922430f8c285b4325da52d69c09451069c93Craig Stout            mActionsRow.setFadingLeftEdgeLength(fadeLength);
28518c8048f17940359b8bce99cb46d24337bff8997Dake Gu            mDetailsDescriptionViewHolder =
28618c8048f17940359b8bce99cb46d24337bff8997Dake Gu                    detailsPresenter.onCreateViewHolder(mDetailsDescriptionFrame);
28718c8048f17940359b8bce99cb46d24337bff8997Dake Gu            mDetailsDescriptionFrame.addView(mDetailsDescriptionViewHolder.view);
288a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        }
289a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    }
290a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
29199ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    final Presenter mDetailsPresenter;
29299ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    OnActionClickedListener mActionClickedListener;
293cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout
294d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    private int mBackgroundColor = Color.TRANSPARENT;
295d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    private boolean mBackgroundColorSet;
296d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    private boolean mIsStyleLarge = true;
297a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
2984121f22713bbed467a977ec0d867ef53989ff374Dake Gu    private DetailsOverviewSharedElementHelper mSharedElementHelper;
2994121f22713bbed467a977ec0d867ef53989ff374Dake Gu
300a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    /**
30180d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn     * Constructor for a DetailsOverviewRowPresenter.
30280d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn     *
30380d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn     * @param detailsPresenter The {@link Presenter} used to render the detailed
30480d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn     *        description of the row.
305a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn     */
306a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    public DetailsOverviewRowPresenter(Presenter detailsPresenter) {
307d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout        setHeaderPresenter(null);
308a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        setSelectEffectEnabled(false);
309a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        mDetailsPresenter = detailsPresenter;
310a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    }
311a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
31270c858a5ca5b7ed9862e2edfa43912faecf42f96Tim Kilbourn    /**
31380d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn     * Sets the listener for Action click events.
31470c858a5ca5b7ed9862e2edfa43912faecf42f96Tim Kilbourn     */
31570c858a5ca5b7ed9862e2edfa43912faecf42f96Tim Kilbourn    public void setOnActionClickedListener(OnActionClickedListener listener) {
316cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout        mActionClickedListener = listener;
31770c858a5ca5b7ed9862e2edfa43912faecf42f96Tim Kilbourn    }
31870c858a5ca5b7ed9862e2edfa43912faecf42f96Tim Kilbourn
31970c858a5ca5b7ed9862e2edfa43912faecf42f96Tim Kilbourn    /**
320a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Returns the listener for Action click events.
32170c858a5ca5b7ed9862e2edfa43912faecf42f96Tim Kilbourn     */
32270c858a5ca5b7ed9862e2edfa43912faecf42f96Tim Kilbourn    public OnActionClickedListener getOnActionClickedListener() {
323cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout        return mActionClickedListener;
32470c858a5ca5b7ed9862e2edfa43912faecf42f96Tim Kilbourn    }
32570c858a5ca5b7ed9862e2edfa43912faecf42f96Tim Kilbourn
326d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    /**
32780d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn     * Sets the background color.  If not set, a default from the theme will be used.
328d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout     */
32970acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye    public void setBackgroundColor(@ColorInt int color) {
330d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout        mBackgroundColor = color;
331d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout        mBackgroundColorSet = true;
332d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    }
333d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout
334d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    /**
33580d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn     * Returns the background color.  If no background color was set, transparent
33680d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn     * is returned.
337d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout     */
33870acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye    @ColorInt
339d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    public int getBackgroundColor() {
340d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout        return mBackgroundColor;
341d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    }
342d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout
343d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    /**
34480d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn     * Sets the layout style to be large or small. This affects the height of
34580d04d2265fe28800fcbc7e8cc7d6d229a7913d8Tim Kilbourn     * the overview, including the text description. The default is large.
346d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout     */
347d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    public void setStyleLarge(boolean large) {
348d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout        mIsStyleLarge = large;
349d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    }
350d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout
351d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    /**
352d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout     * Returns true if the layout style is large.
353d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout     */
354d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    public boolean isStyleLarge() {
355d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout        return mIsStyleLarge;
356d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    }
357d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout
3589de363b8db05106b03d115c266859fe200d41db7Dake Gu    /**
359a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Sets the enter transition of target activity to be
360d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu     * transiting into overview row created by this presenter.  The transition will
361a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * be cancelled if the overview image is not loaded in the timeout period.
3624121f22713bbed467a977ec0d867ef53989ff374Dake Gu     * <p>
3634121f22713bbed467a977ec0d867ef53989ff374Dake Gu     * It assumes shared element passed from calling activity is an ImageView;
364a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * the shared element transits to overview image on the starting edge of the detail
3654121f22713bbed467a977ec0d867ef53989ff374Dake Gu     * overview row, while bounds of overview row grows and reveals text
366a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * and action buttons.
3674121f22713bbed467a977ec0d867ef53989ff374Dake Gu     * <p>
3684121f22713bbed467a977ec0d867ef53989ff374Dake Gu     * The method must be invoked in target Activity's onCreate().
3699de363b8db05106b03d115c266859fe200d41db7Dake Gu     */
3704121f22713bbed467a977ec0d867ef53989ff374Dake Gu    public final void setSharedElementEnterTransition(Activity activity,
371d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu            String sharedElementName, long timeoutMs) {
3724121f22713bbed467a977ec0d867ef53989ff374Dake Gu        if (mSharedElementHelper == null) {
3734121f22713bbed467a977ec0d867ef53989ff374Dake Gu            mSharedElementHelper = new DetailsOverviewSharedElementHelper();
3744121f22713bbed467a977ec0d867ef53989ff374Dake Gu        }
375d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu        mSharedElementHelper.setSharedElementEnterTransition(activity, sharedElementName,
376d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                timeoutMs);
377d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu    }
378d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu
379d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu    /**
380a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Sets the enter transition of target activity to be
381d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu     * transiting into overview row created by this presenter.  The transition will
382d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu     * be cancelled if overview image is not loaded in a default timeout period.
383d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu     * <p>
384d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu     * It assumes shared element passed from calling activity is an ImageView;
385a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * the shared element transits to overview image on the starting edge of the detail
386d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu     * overview row, while bounds of overview row grows and reveals text
387a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * and action buttons.
388d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu     * <p>
389d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu     * The method must be invoked in target Activity's onCreate().
390d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu     */
391d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu    public final void setSharedElementEnterTransition(Activity activity,
392d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu            String sharedElementName) {
393d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu        setSharedElementEnterTransition(activity, sharedElementName, DEFAULT_TIMEOUT);
3949de363b8db05106b03d115c266859fe200d41db7Dake Gu    }
3959de363b8db05106b03d115c266859fe200d41db7Dake Gu
396d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    private int getDefaultBackgroundColor(Context context) {
397d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout        TypedValue outValue = new TypedValue();
39846443cb5b092f1d9156342645088eead9da026f6Dake Gu        if (context.getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true)) {
39946443cb5b092f1d9156342645088eead9da026f6Dake Gu            return context.getResources().getColor(outValue.resourceId);
40046443cb5b092f1d9156342645088eead9da026f6Dake Gu        }
40146443cb5b092f1d9156342645088eead9da026f6Dake Gu        return context.getResources().getColor(R.color.lb_default_brand_color);
402d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    }
403d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout
404d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu    @Override
405cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout    protected void onRowViewSelected(RowPresenter.ViewHolder vh, boolean selected) {
406cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout        super.onRowViewSelected(vh, selected);
407cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout        if (selected) {
408cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout            ((ViewHolder) vh).dispatchItemSelection(null);
409cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout        }
410cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout    }
411cf992de2d34abb8228dc6cb39fffe97346823a37Craig Stout
412a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    @Override
413a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) {
414a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        View v = LayoutInflater.from(parent.getContext())
415a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn            .inflate(R.layout.lb_details_overview, parent, false);
41618c8048f17940359b8bce99cb46d24337bff8997Dake Gu        ViewHolder vh = new ViewHolder(v, mDetailsPresenter);
417a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
41850ea3557b75826b3f51480715df1973472e345c4Craig Stout        initDetailsOverview(vh);
419d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout
420a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        return vh;
421a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    }
422a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
423e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout    private int getCardHeight(Context context) {
424d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout        int resId = mIsStyleLarge ? R.dimen.lb_details_overview_height_large :
425d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout            R.dimen.lb_details_overview_height_small;
426e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        return context.getResources().getDimensionPixelSize(resId);
427e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout    }
428d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout
42960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout    private void initDetailsOverview(final ViewHolder vh) {
43071fddded48048acfa744ac352166770c91a1c2b1Dake Gu        vh.mActionBridgeAdapter = new ActionsItemBridgeAdapter(vh);
43126c145aadca16cba3f294cc93c36edc6e9c98e6aCraig Stout        final View overview = vh.mOverviewFrame;
43250ea3557b75826b3f51480715df1973472e345c4Craig Stout        ViewGroup.LayoutParams lp = overview.getLayoutParams();
433e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        lp.height = getCardHeight(overview.getContext());
43450ea3557b75826b3f51480715df1973472e345c4Craig Stout        overview.setLayoutParams(lp);
435d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout
43609d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout        if (!getSelectEffectEnabled()) {
43709d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout            vh.mOverviewFrame.setForeground(null);
43809d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout        }
43960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout        vh.mActionsRow.setOnUnhandledKeyListener(new BaseGridView.OnUnhandledKeyListener() {
44060bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout            @Override
44160bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout            public boolean onUnhandledKey(KeyEvent event) {
44260bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout                if (vh.getOnKeyListener() != null) {
44360bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout                    if (vh.getOnKeyListener().onKey(vh.view, event.getKeyCode(), event)) {
44460bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout                        return true;
44560bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout                    }
44660bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout                }
44760bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout                return false;
44860bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout            }
44960bb6af2e336072921f5d3c3861e86b3cc6241b3Craig Stout        });
450d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout    }
451d2c235afaa4119599fd8bfc9bff65c5af9a8fdc1Craig Stout
4527728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout    private static int getNonNegativeWidth(Drawable drawable) {
4537728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout        final int width = (drawable == null) ? 0 : drawable.getIntrinsicWidth();
4547728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout        return (width > 0 ? width : 0);
4557728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout    }
4567728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout
4577728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout    private static int getNonNegativeHeight(Drawable drawable) {
4587728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout        final int height = (drawable == null) ? 0 : drawable.getIntrinsicHeight();
4597728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout        return (height > 0 ? height : 0);
4607728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout    }
4617728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout
46299ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    void bindImageDrawable(ViewHolder vh) {
463d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        DetailsOverviewRow row = (DetailsOverviewRow) vh.getRow();
464e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout
465e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        ViewGroup.MarginLayoutParams layoutParams =
466e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout                (ViewGroup.MarginLayoutParams) vh.mImageView.getLayoutParams();
467e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        final int cardHeight = getCardHeight(vh.mImageView.getContext());
468e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        final int verticalMargin = vh.mImageView.getResources().getDimensionPixelSize(
469e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout                R.dimen.lb_details_overview_image_margin_vertical);
470e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        final int horizontalMargin = vh.mImageView.getResources().getDimensionPixelSize(
471e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout                R.dimen.lb_details_overview_image_margin_horizontal);
4727728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout        final int drawableWidth = getNonNegativeWidth(row.getImageDrawable());
4737728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout        final int drawableHeight = getNonNegativeHeight(row.getImageDrawable());
4747728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout
475e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        boolean scaleImage = row.isImageScaleUpAllowed();
476e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        boolean useMargin = false;
477e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout
4787728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout        if (row.getImageDrawable() != null) {
4797728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout            boolean landscape = false;
4807728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout
4817728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout            // If large style and landscape image we always use margin.
4827728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout            if (drawableWidth > drawableHeight) {
4837728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout                landscape = true;
4847728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout                if (mIsStyleLarge) {
4857728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout                    useMargin = true;
4867728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout                }
487e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout            }
4887728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout            // If long dimension bigger than the card height we scale down.
4893103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            if ((landscape && drawableWidth > cardHeight)
4903103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                    || (!landscape && drawableHeight > cardHeight)) {
491e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout                scaleImage = true;
492e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout            }
4937728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout            // If we're not scaling to fit the card height then we always use margin.
4947728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout            if (!scaleImage) {
4957728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout                useMargin = true;
4967728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout            }
4977728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout            // If using margin than may need to scale down.
4987728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout            if (useMargin && !scaleImage) {
4997728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout                if (landscape && drawableWidth > cardHeight - horizontalMargin) {
5007728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout                    scaleImage = true;
5017728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout                } else if (!landscape && drawableHeight > cardHeight - 2 * verticalMargin) {
5027728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout                    scaleImage = true;
5037728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout                }
5047728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout            }
505e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        }
506e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout
5074f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout        final int bgColor = mBackgroundColorSet ? mBackgroundColor :
5084f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout            getDefaultBackgroundColor(vh.mOverviewView.getContext());
5094f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout
510e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        if (useMargin) {
5114e602840ed6741b44a536826799625ad0be4b3c6Kris Giesing            layoutParams.setMarginStart(horizontalMargin);
512e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout            layoutParams.topMargin = layoutParams.bottomMargin = verticalMargin;
5136b447e693090017258eb48a51ae4119fb0f5119eCraig Stout            vh.mOverviewFrame.setBackgroundColor(bgColor);
51472a2146f4c3e6dbb84a5f9f92e7ab42d142dab04Dake Gu            vh.mRightPanel.setBackground(null);
515836443f4a3b69eb7a88ffeb65a39e11439dee55eDake Gu            vh.mImageView.setBackground(null);
516e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        } else {
517e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout            layoutParams.leftMargin = layoutParams.topMargin = layoutParams.bottomMargin = 0;
5184f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout            vh.mRightPanel.setBackgroundColor(bgColor);
5194f34a05cdf73b68c3b2eb8678f740ab15225126aCraig Stout            vh.mImageView.setBackgroundColor(bgColor);
5206b447e693090017258eb48a51ae4119fb0f5119eCraig Stout            vh.mOverviewFrame.setBackground(null);
521e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        }
5229cc4c25ccaefdb9fd3186323f0d1520ef4458aa8Jake Wharton        RoundedRectHelper.setClipToRoundedOutline(vh.mOverviewFrame, true);
5236b447e693090017258eb48a51ae4119fb0f5119eCraig Stout
524e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        if (scaleImage) {
525e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout            vh.mImageView.setScaleType(ImageView.ScaleType.FIT_START);
526e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout            vh.mImageView.setAdjustViewBounds(true);
527e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout            vh.mImageView.setMaxWidth(cardHeight);
528e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout            layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
529e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout            layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
530e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        } else {
531e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout            vh.mImageView.setScaleType(ImageView.ScaleType.CENTER);
532e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout            vh.mImageView.setAdjustViewBounds(false);
533e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout            layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
534e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout            // Limit width to the card height
5357728d53c5c50e8ed807e8f4a189e34684de04800Craig Stout            layoutParams.width = Math.min(cardHeight, drawableWidth);
536e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        }
537e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        vh.mImageView.setLayoutParams(layoutParams);
538e23ea69ec54eb70d17239ba671fcd75563780553Craig Stout        vh.mImageView.setImageDrawable(row.getImageDrawable());
5394121f22713bbed467a977ec0d867ef53989ff374Dake Gu        if (row.getImageDrawable() != null && mSharedElementHelper != null) {
5404121f22713bbed467a977ec0d867ef53989ff374Dake Gu            mSharedElementHelper.onBindToDrawable(vh);
5414121f22713bbed467a977ec0d867ef53989ff374Dake Gu        }
542a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    }
543a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn
544a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    @Override
545d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu    protected void onBindRowViewHolder(RowPresenter.ViewHolder holder, Object item) {
546d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        super.onBindRowViewHolder(holder, item);
547d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu
548d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        DetailsOverviewRow row = (DetailsOverviewRow) item;
549d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        ViewHolder vh = (ViewHolder) holder;
550d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu
551d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        bindImageDrawable(vh);
552d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        mDetailsPresenter.onBindViewHolder(vh.mDetailsDescriptionViewHolder, row.getItem());
553d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        vh.bindActions(row.getActionsAdapter());
554d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        row.addListener(vh.mListener);
555d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu    }
556d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu
557d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu    @Override
558cb13a318e577e14461eb008071dddf762847de42Dake Gu    protected void onUnbindRowViewHolder(RowPresenter.ViewHolder holder) {
559a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        ViewHolder vh = (ViewHolder) holder;
560d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        DetailsOverviewRow dor = (DetailsOverviewRow) vh.getRow();
561d825ff3727407a154a35e20b3a9adc79e57879b9Dake Gu        dor.removeListener(vh.mListener);
562a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        if (vh.mDetailsDescriptionViewHolder != null) {
563a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn            mDetailsPresenter.onUnbindViewHolder(vh.mDetailsDescriptionViewHolder);
564a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn        }
565fc8f0f06c93c224d86b85c8b9f7ae737968fd797Dake Gu        super.onUnbindRowViewHolder(holder);
566a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn    }
56709d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout
56809d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout    @Override
56909d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout    public final boolean isUsingDefaultSelectEffect() {
57009d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout        return false;
57109d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout    }
57209d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout
57309d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout    @Override
57409d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout    protected void onSelectLevelChanged(RowPresenter.ViewHolder holder) {
57509d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout        super.onSelectLevelChanged(holder);
57609d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout        if (getSelectEffectEnabled()) {
57709d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout            ViewHolder vh = (ViewHolder) holder;
57809d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout            int dimmedColor = vh.mColorDimmer.getPaint().getColor();
57909d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout            ((ColorDrawable) vh.mOverviewFrame.getForeground().mutate()).setColor(dimmedColor);
58009d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout        }
58109d52d76912e3689cc2b58b7bb3f44b923915fd8Craig Stout    }
58226d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout
58326d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout    @Override
58426d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout    protected void onRowViewAttachedToWindow(RowPresenter.ViewHolder vh) {
58526d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout        super.onRowViewAttachedToWindow(vh);
58626d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout        if (mDetailsPresenter != null) {
58726d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout            mDetailsPresenter.onViewAttachedToWindow(
58826d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout                    ((ViewHolder) vh).mDetailsDescriptionViewHolder);
58926d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout        }
59026d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout    }
59126d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout
59226d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout    @Override
59326d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout    protected void onRowViewDetachedFromWindow(RowPresenter.ViewHolder vh) {
59426d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout        super.onRowViewDetachedFromWindow(vh);
59526d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout        if (mDetailsPresenter != null) {
59626d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout            mDetailsPresenter.onViewDetachedFromWindow(
59726d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout                    ((ViewHolder) vh).mDetailsDescriptionViewHolder);
59826d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout        }
59926d11212c4a66b075807888caacac5ee7fc10dc1Craig Stout    }
600a83005b70853ea52c5d98910762344de16b850a8Tim Kilbourn}
601