Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
      5  * in compliance with the License. You may obtain a copy of the License at
      6  *
      7  * http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the License
     10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
     11  * or implied. See the License for the specific language governing permissions and limitations under
     12  * the License.
     13  */
     14 package androidx.leanback.widget;
     15 
     16 import android.app.Activity;
     17 import android.content.Context;
     18 import android.graphics.Color;
     19 import android.graphics.drawable.ColorDrawable;
     20 import android.graphics.drawable.Drawable;
     21 import android.os.Handler;
     22 import android.util.Log;
     23 import android.util.TypedValue;
     24 import android.view.KeyEvent;
     25 import android.view.LayoutInflater;
     26 import android.view.View;
     27 import android.view.ViewGroup;
     28 import android.widget.FrameLayout;
     29 import android.widget.ImageView;
     30 
     31 import androidx.annotation.ColorInt;
     32 import androidx.leanback.R;
     33 import androidx.recyclerview.widget.RecyclerView;
     34 
     35 /**
     36  * Renders a {@link DetailsOverviewRow} to display an overview of an item.
     37  * Typically this row will be the first row in a fragment
     38  * such as the {@link androidx.leanback.app.DetailsFragment
     39  * DetailsFragment}.  The View created by the DetailsOverviewRowPresenter is made in three parts:
     40  * ImageView on the left, action list view on the bottom and a customizable detailed
     41  * description view on the right.
     42  *
     43  * <p>The detailed description is rendered using a {@link Presenter} passed in
     44  * {@link #DetailsOverviewRowPresenter(Presenter)}.  Typically this will be an instance of
     45  * {@link AbstractDetailsDescriptionPresenter}.  The application can access the
     46  * detailed description ViewHolder from {@link ViewHolder#mDetailsDescriptionViewHolder}.
     47  * </p>
     48  *
     49  * <p>
     50  * To participate in activity transition, call {@link #setSharedElementEnterTransition(Activity,
     51  * String)} during Activity's onCreate().
     52  * </p>
     53  *
     54  * <p>
     55  * Because transition support and layout are fully controlled by DetailsOverviewRowPresenter,
     56  * developer can not override DetailsOverviewRowPresenter.ViewHolder for adding/replacing views
     57  * of DetailsOverviewRowPresenter.  If further customization is required beyond replacing
     58  * the detailed description, the application should create a new row presenter class.
     59  * </p>
     60  * @deprecated  Use {@link FullWidthDetailsOverviewRowPresenter}
     61  */
     62 @Deprecated
     63 public class DetailsOverviewRowPresenter extends RowPresenter {
     64 
     65     static final String TAG = "DetailsOverviewRowP";
     66     static final boolean DEBUG = false;
     67 
     68     private static final int MORE_ACTIONS_FADE_MS = 100;
     69     private static final long DEFAULT_TIMEOUT = 5000;
     70 
     71     class ActionsItemBridgeAdapter extends ItemBridgeAdapter {
     72         DetailsOverviewRowPresenter.ViewHolder mViewHolder;
     73 
     74         ActionsItemBridgeAdapter(DetailsOverviewRowPresenter.ViewHolder viewHolder) {
     75             mViewHolder = viewHolder;
     76         }
     77 
     78         @Override
     79         public void onBind(final ItemBridgeAdapter.ViewHolder ibvh) {
     80             if (mViewHolder.getOnItemViewClickedListener() != null
     81                     || mActionClickedListener != null) {
     82                 ibvh.getPresenter().setOnClickListener(
     83                         ibvh.getViewHolder(), new View.OnClickListener() {
     84                             @Override
     85                             public void onClick(View v) {
     86                                 if (mViewHolder.getOnItemViewClickedListener() != null) {
     87                                     mViewHolder.getOnItemViewClickedListener().onItemClicked(
     88                                             ibvh.getViewHolder(), ibvh.getItem(),
     89                                             mViewHolder, mViewHolder.getRow());
     90                                 }
     91                                 if (mActionClickedListener != null) {
     92                                     mActionClickedListener.onActionClicked((Action) ibvh.getItem());
     93                                 }
     94                             }
     95                         });
     96             }
     97         }
     98         @Override
     99         public void onUnbind(final ItemBridgeAdapter.ViewHolder ibvh) {
    100             if (mViewHolder.getOnItemViewClickedListener() != null
    101                     || mActionClickedListener != null) {
    102                 ibvh.getPresenter().setOnClickListener(ibvh.getViewHolder(), null);
    103             }
    104         }
    105         @Override
    106         public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) {
    107             // Remove first to ensure we don't add ourselves more than once.
    108             viewHolder.itemView.removeOnLayoutChangeListener(mViewHolder.mLayoutChangeListener);
    109             viewHolder.itemView.addOnLayoutChangeListener(mViewHolder.mLayoutChangeListener);
    110         }
    111         @Override
    112         public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder viewHolder) {
    113             viewHolder.itemView.removeOnLayoutChangeListener(mViewHolder.mLayoutChangeListener);
    114             mViewHolder.checkFirstAndLastPosition(false);
    115         }
    116     }
    117 
    118     /**
    119      * A ViewHolder for the DetailsOverviewRow.
    120      */
    121     public final class ViewHolder extends RowPresenter.ViewHolder {
    122         final FrameLayout mOverviewFrame;
    123         final ViewGroup mOverviewView;
    124         final ImageView mImageView;
    125         final ViewGroup mRightPanel;
    126         final FrameLayout mDetailsDescriptionFrame;
    127         final HorizontalGridView mActionsRow;
    128         public final Presenter.ViewHolder mDetailsDescriptionViewHolder;
    129         int mNumItems;
    130         boolean mShowMoreRight;
    131         boolean mShowMoreLeft;
    132         ItemBridgeAdapter mActionBridgeAdapter;
    133         final Handler mHandler = new Handler();
    134 
    135         final Runnable mUpdateDrawableCallback = new Runnable() {
    136             @Override
    137             public void run() {
    138                 bindImageDrawable(ViewHolder.this);
    139             }
    140         };
    141 
    142         final DetailsOverviewRow.Listener mListener = new DetailsOverviewRow.Listener() {
    143             @Override
    144             public void onImageDrawableChanged(DetailsOverviewRow row) {
    145                 mHandler.removeCallbacks(mUpdateDrawableCallback);
    146                 mHandler.post(mUpdateDrawableCallback);
    147             }
    148 
    149             @Override
    150             public void onItemChanged(DetailsOverviewRow row) {
    151                 if (mDetailsDescriptionViewHolder != null) {
    152                     mDetailsPresenter.onUnbindViewHolder(mDetailsDescriptionViewHolder);
    153                 }
    154                 mDetailsPresenter.onBindViewHolder(mDetailsDescriptionViewHolder, row.getItem());
    155             }
    156 
    157             @Override
    158             public void onActionsAdapterChanged(DetailsOverviewRow row) {
    159                 bindActions(row.getActionsAdapter());
    160             }
    161         };
    162 
    163         void bindActions(ObjectAdapter adapter) {
    164             mActionBridgeAdapter.setAdapter(adapter);
    165             mActionsRow.setAdapter(mActionBridgeAdapter);
    166             mNumItems = mActionBridgeAdapter.getItemCount();
    167 
    168             mShowMoreRight = false;
    169             mShowMoreLeft = true;
    170             showMoreLeft(false);
    171         }
    172 
    173         final View.OnLayoutChangeListener mLayoutChangeListener =
    174                 new View.OnLayoutChangeListener() {
    175 
    176             @Override
    177             public void onLayoutChange(View v, int left, int top, int right,
    178                     int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
    179                 if (DEBUG) Log.v(TAG, "onLayoutChange " + v);
    180                 checkFirstAndLastPosition(false);
    181             }
    182         };
    183 
    184         final OnChildSelectedListener mChildSelectedListener = new OnChildSelectedListener() {
    185             @Override
    186             public void onChildSelected(ViewGroup parent, View view, int position, long id) {
    187                 dispatchItemSelection(view);
    188             }
    189         };
    190 
    191         void dispatchItemSelection(View view) {
    192             if (!isSelected()) {
    193                 return;
    194             }
    195             ItemBridgeAdapter.ViewHolder ibvh = (ItemBridgeAdapter.ViewHolder) (view != null
    196                     ? mActionsRow.getChildViewHolder(view)
    197                     : mActionsRow.findViewHolderForPosition(mActionsRow.getSelectedPosition()));
    198             if (ibvh == null) {
    199                 if (getOnItemViewSelectedListener() != null) {
    200                     getOnItemViewSelectedListener().onItemSelected(null, null,
    201                             ViewHolder.this, getRow());
    202                 }
    203             } else {
    204                 if (getOnItemViewSelectedListener() != null) {
    205                     getOnItemViewSelectedListener().onItemSelected(ibvh.getViewHolder(), ibvh.getItem(),
    206                             ViewHolder.this, getRow());
    207                 }
    208             }
    209         };
    210 
    211         final RecyclerView.OnScrollListener mScrollListener =
    212                 new RecyclerView.OnScrollListener() {
    213 
    214             @Override
    215             public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    216             }
    217             @Override
    218             public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    219                 checkFirstAndLastPosition(true);
    220             }
    221         };
    222 
    223         private int getViewCenter(View view) {
    224             return (view.getRight() - view.getLeft()) / 2;
    225         }
    226 
    227         void checkFirstAndLastPosition(boolean fromScroll) {
    228             RecyclerView.ViewHolder viewHolder;
    229 
    230             viewHolder = mActionsRow.findViewHolderForPosition(mNumItems - 1);
    231             boolean showRight = (viewHolder == null
    232                     || viewHolder.itemView.getRight() > mActionsRow.getWidth());
    233 
    234             viewHolder = mActionsRow.findViewHolderForPosition(0);
    235             boolean showLeft = (viewHolder == null || viewHolder.itemView.getLeft() < 0);
    236 
    237             if (DEBUG) {
    238                 Log.v(TAG, "checkFirstAndLast fromScroll " + fromScroll
    239                         + " showRight " + showRight + " showLeft " + showLeft);
    240             }
    241 
    242             showMoreRight(showRight);
    243             showMoreLeft(showLeft);
    244         }
    245 
    246         private void showMoreLeft(boolean show) {
    247             if (show != mShowMoreLeft) {
    248                 mActionsRow.setFadingLeftEdge(show);
    249                 mShowMoreLeft = show;
    250             }
    251         }
    252 
    253         private void showMoreRight(boolean show) {
    254             if (show != mShowMoreRight) {
    255                 mActionsRow.setFadingRightEdge(show);
    256                 mShowMoreRight = show;
    257             }
    258         }
    259 
    260         /**
    261          * Constructor for the ViewHolder.
    262          *
    263          * @param rootView The root View that this view holder will be attached
    264          *        to.
    265          */
    266         public ViewHolder(View rootView, Presenter detailsPresenter) {
    267             super(rootView);
    268             mOverviewFrame = (FrameLayout) rootView.findViewById(R.id.details_frame);
    269             mOverviewView = (ViewGroup) rootView.findViewById(R.id.details_overview);
    270             mImageView = (ImageView) rootView.findViewById(R.id.details_overview_image);
    271             mRightPanel = (ViewGroup) rootView.findViewById(R.id.details_overview_right_panel);
    272             mDetailsDescriptionFrame =
    273                     (FrameLayout) mRightPanel.findViewById(R.id.details_overview_description);
    274             mActionsRow =
    275                     (HorizontalGridView) mRightPanel.findViewById(R.id.details_overview_actions);
    276             mActionsRow.setHasOverlappingRendering(false);
    277             mActionsRow.setOnScrollListener(mScrollListener);
    278             mActionsRow.setAdapter(mActionBridgeAdapter);
    279             mActionsRow.setOnChildSelectedListener(mChildSelectedListener);
    280 
    281             final int fadeLength = rootView.getResources().getDimensionPixelSize(
    282                     R.dimen.lb_details_overview_actions_fade_size);
    283             mActionsRow.setFadingRightEdgeLength(fadeLength);
    284             mActionsRow.setFadingLeftEdgeLength(fadeLength);
    285             mDetailsDescriptionViewHolder =
    286                     detailsPresenter.onCreateViewHolder(mDetailsDescriptionFrame);
    287             mDetailsDescriptionFrame.addView(mDetailsDescriptionViewHolder.view);
    288         }
    289     }
    290 
    291     final Presenter mDetailsPresenter;
    292     OnActionClickedListener mActionClickedListener;
    293 
    294     private int mBackgroundColor = Color.TRANSPARENT;
    295     private boolean mBackgroundColorSet;
    296     private boolean mIsStyleLarge = true;
    297 
    298     private DetailsOverviewSharedElementHelper mSharedElementHelper;
    299 
    300     /**
    301      * Constructor for a DetailsOverviewRowPresenter.
    302      *
    303      * @param detailsPresenter The {@link Presenter} used to render the detailed
    304      *        description of the row.
    305      */
    306     public DetailsOverviewRowPresenter(Presenter detailsPresenter) {
    307         setHeaderPresenter(null);
    308         setSelectEffectEnabled(false);
    309         mDetailsPresenter = detailsPresenter;
    310     }
    311 
    312     /**
    313      * Sets the listener for Action click events.
    314      */
    315     public void setOnActionClickedListener(OnActionClickedListener listener) {
    316         mActionClickedListener = listener;
    317     }
    318 
    319     /**
    320      * Returns the listener for Action click events.
    321      */
    322     public OnActionClickedListener getOnActionClickedListener() {
    323         return mActionClickedListener;
    324     }
    325 
    326     /**
    327      * Sets the background color.  If not set, a default from the theme will be used.
    328      */
    329     public void setBackgroundColor(@ColorInt int color) {
    330         mBackgroundColor = color;
    331         mBackgroundColorSet = true;
    332     }
    333 
    334     /**
    335      * Returns the background color.  If no background color was set, transparent
    336      * is returned.
    337      */
    338     @ColorInt
    339     public int getBackgroundColor() {
    340         return mBackgroundColor;
    341     }
    342 
    343     /**
    344      * Sets the layout style to be large or small. This affects the height of
    345      * the overview, including the text description. The default is large.
    346      */
    347     public void setStyleLarge(boolean large) {
    348         mIsStyleLarge = large;
    349     }
    350 
    351     /**
    352      * Returns true if the layout style is large.
    353      */
    354     public boolean isStyleLarge() {
    355         return mIsStyleLarge;
    356     }
    357 
    358     /**
    359      * Sets the enter transition of target activity to be
    360      * transiting into overview row created by this presenter.  The transition will
    361      * be cancelled if the overview image is not loaded in the timeout period.
    362      * <p>
    363      * It assumes shared element passed from calling activity is an ImageView;
    364      * the shared element transits to overview image on the starting edge of the detail
    365      * overview row, while bounds of overview row grows and reveals text
    366      * and action buttons.
    367      * <p>
    368      * The method must be invoked in target Activity's onCreate().
    369      */
    370     public final void setSharedElementEnterTransition(Activity activity,
    371             String sharedElementName, long timeoutMs) {
    372         if (mSharedElementHelper == null) {
    373             mSharedElementHelper = new DetailsOverviewSharedElementHelper();
    374         }
    375         mSharedElementHelper.setSharedElementEnterTransition(activity, sharedElementName,
    376                 timeoutMs);
    377     }
    378 
    379     /**
    380      * Sets the enter transition of target activity to be
    381      * transiting into overview row created by this presenter.  The transition will
    382      * be cancelled if overview image is not loaded in a default timeout period.
    383      * <p>
    384      * It assumes shared element passed from calling activity is an ImageView;
    385      * the shared element transits to overview image on the starting edge of the detail
    386      * overview row, while bounds of overview row grows and reveals text
    387      * and action buttons.
    388      * <p>
    389      * The method must be invoked in target Activity's onCreate().
    390      */
    391     public final void setSharedElementEnterTransition(Activity activity,
    392             String sharedElementName) {
    393         setSharedElementEnterTransition(activity, sharedElementName, DEFAULT_TIMEOUT);
    394     }
    395 
    396     private int getDefaultBackgroundColor(Context context) {
    397         TypedValue outValue = new TypedValue();
    398         if (context.getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true)) {
    399             return context.getResources().getColor(outValue.resourceId);
    400         }
    401         return context.getResources().getColor(R.color.lb_default_brand_color);
    402     }
    403 
    404     @Override
    405     protected void onRowViewSelected(RowPresenter.ViewHolder vh, boolean selected) {
    406         super.onRowViewSelected(vh, selected);
    407         if (selected) {
    408             ((ViewHolder) vh).dispatchItemSelection(null);
    409         }
    410     }
    411 
    412     @Override
    413     protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) {
    414         View v = LayoutInflater.from(parent.getContext())
    415             .inflate(R.layout.lb_details_overview, parent, false);
    416         ViewHolder vh = new ViewHolder(v, mDetailsPresenter);
    417 
    418         initDetailsOverview(vh);
    419 
    420         return vh;
    421     }
    422 
    423     private int getCardHeight(Context context) {
    424         int resId = mIsStyleLarge ? R.dimen.lb_details_overview_height_large :
    425             R.dimen.lb_details_overview_height_small;
    426         return context.getResources().getDimensionPixelSize(resId);
    427     }
    428 
    429     private void initDetailsOverview(final ViewHolder vh) {
    430         vh.mActionBridgeAdapter = new ActionsItemBridgeAdapter(vh);
    431         final View overview = vh.mOverviewFrame;
    432         ViewGroup.LayoutParams lp = overview.getLayoutParams();
    433         lp.height = getCardHeight(overview.getContext());
    434         overview.setLayoutParams(lp);
    435 
    436         if (!getSelectEffectEnabled()) {
    437             vh.mOverviewFrame.setForeground(null);
    438         }
    439         vh.mActionsRow.setOnUnhandledKeyListener(new BaseGridView.OnUnhandledKeyListener() {
    440             @Override
    441             public boolean onUnhandledKey(KeyEvent event) {
    442                 if (vh.getOnKeyListener() != null) {
    443                     if (vh.getOnKeyListener().onKey(vh.view, event.getKeyCode(), event)) {
    444                         return true;
    445                     }
    446                 }
    447                 return false;
    448             }
    449         });
    450     }
    451 
    452     private static int getNonNegativeWidth(Drawable drawable) {
    453         final int width = (drawable == null) ? 0 : drawable.getIntrinsicWidth();
    454         return (width > 0 ? width : 0);
    455     }
    456 
    457     private static int getNonNegativeHeight(Drawable drawable) {
    458         final int height = (drawable == null) ? 0 : drawable.getIntrinsicHeight();
    459         return (height > 0 ? height : 0);
    460     }
    461 
    462     void bindImageDrawable(ViewHolder vh) {
    463         DetailsOverviewRow row = (DetailsOverviewRow) vh.getRow();
    464 
    465         ViewGroup.MarginLayoutParams layoutParams =
    466                 (ViewGroup.MarginLayoutParams) vh.mImageView.getLayoutParams();
    467         final int cardHeight = getCardHeight(vh.mImageView.getContext());
    468         final int verticalMargin = vh.mImageView.getResources().getDimensionPixelSize(
    469                 R.dimen.lb_details_overview_image_margin_vertical);
    470         final int horizontalMargin = vh.mImageView.getResources().getDimensionPixelSize(
    471                 R.dimen.lb_details_overview_image_margin_horizontal);
    472         final int drawableWidth = getNonNegativeWidth(row.getImageDrawable());
    473         final int drawableHeight = getNonNegativeHeight(row.getImageDrawable());
    474 
    475         boolean scaleImage = row.isImageScaleUpAllowed();
    476         boolean useMargin = false;
    477 
    478         if (row.getImageDrawable() != null) {
    479             boolean landscape = false;
    480 
    481             // If large style and landscape image we always use margin.
    482             if (drawableWidth > drawableHeight) {
    483                 landscape = true;
    484                 if (mIsStyleLarge) {
    485                     useMargin = true;
    486                 }
    487             }
    488             // If long dimension bigger than the card height we scale down.
    489             if ((landscape && drawableWidth > cardHeight)
    490                     || (!landscape && drawableHeight > cardHeight)) {
    491                 scaleImage = true;
    492             }
    493             // If we're not scaling to fit the card height then we always use margin.
    494             if (!scaleImage) {
    495                 useMargin = true;
    496             }
    497             // If using margin than may need to scale down.
    498             if (useMargin && !scaleImage) {
    499                 if (landscape && drawableWidth > cardHeight - horizontalMargin) {
    500                     scaleImage = true;
    501                 } else if (!landscape && drawableHeight > cardHeight - 2 * verticalMargin) {
    502                     scaleImage = true;
    503                 }
    504             }
    505         }
    506 
    507         final int bgColor = mBackgroundColorSet ? mBackgroundColor :
    508             getDefaultBackgroundColor(vh.mOverviewView.getContext());
    509 
    510         if (useMargin) {
    511             layoutParams.setMarginStart(horizontalMargin);
    512             layoutParams.topMargin = layoutParams.bottomMargin = verticalMargin;
    513             vh.mOverviewFrame.setBackgroundColor(bgColor);
    514             vh.mRightPanel.setBackground(null);
    515             vh.mImageView.setBackground(null);
    516         } else {
    517             layoutParams.leftMargin = layoutParams.topMargin = layoutParams.bottomMargin = 0;
    518             vh.mRightPanel.setBackgroundColor(bgColor);
    519             vh.mImageView.setBackgroundColor(bgColor);
    520             vh.mOverviewFrame.setBackground(null);
    521         }
    522         RoundedRectHelper.setClipToRoundedOutline(vh.mOverviewFrame, true);
    523 
    524         if (scaleImage) {
    525             vh.mImageView.setScaleType(ImageView.ScaleType.FIT_START);
    526             vh.mImageView.setAdjustViewBounds(true);
    527             vh.mImageView.setMaxWidth(cardHeight);
    528             layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
    529             layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
    530         } else {
    531             vh.mImageView.setScaleType(ImageView.ScaleType.CENTER);
    532             vh.mImageView.setAdjustViewBounds(false);
    533             layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
    534             // Limit width to the card height
    535             layoutParams.width = Math.min(cardHeight, drawableWidth);
    536         }
    537         vh.mImageView.setLayoutParams(layoutParams);
    538         vh.mImageView.setImageDrawable(row.getImageDrawable());
    539         if (row.getImageDrawable() != null && mSharedElementHelper != null) {
    540             mSharedElementHelper.onBindToDrawable(vh);
    541         }
    542     }
    543 
    544     @Override
    545     protected void onBindRowViewHolder(RowPresenter.ViewHolder holder, Object item) {
    546         super.onBindRowViewHolder(holder, item);
    547 
    548         DetailsOverviewRow row = (DetailsOverviewRow) item;
    549         ViewHolder vh = (ViewHolder) holder;
    550 
    551         bindImageDrawable(vh);
    552         mDetailsPresenter.onBindViewHolder(vh.mDetailsDescriptionViewHolder, row.getItem());
    553         vh.bindActions(row.getActionsAdapter());
    554         row.addListener(vh.mListener);
    555     }
    556 
    557     @Override
    558     protected void onUnbindRowViewHolder(RowPresenter.ViewHolder holder) {
    559         ViewHolder vh = (ViewHolder) holder;
    560         DetailsOverviewRow dor = (DetailsOverviewRow) vh.getRow();
    561         dor.removeListener(vh.mListener);
    562         if (vh.mDetailsDescriptionViewHolder != null) {
    563             mDetailsPresenter.onUnbindViewHolder(vh.mDetailsDescriptionViewHolder);
    564         }
    565         super.onUnbindRowViewHolder(holder);
    566     }
    567 
    568     @Override
    569     public final boolean isUsingDefaultSelectEffect() {
    570         return false;
    571     }
    572 
    573     @Override
    574     protected void onSelectLevelChanged(RowPresenter.ViewHolder holder) {
    575         super.onSelectLevelChanged(holder);
    576         if (getSelectEffectEnabled()) {
    577             ViewHolder vh = (ViewHolder) holder;
    578             int dimmedColor = vh.mColorDimmer.getPaint().getColor();
    579             ((ColorDrawable) vh.mOverviewFrame.getForeground().mutate()).setColor(dimmedColor);
    580         }
    581     }
    582 
    583     @Override
    584     protected void onRowViewAttachedToWindow(RowPresenter.ViewHolder vh) {
    585         super.onRowViewAttachedToWindow(vh);
    586         if (mDetailsPresenter != null) {
    587             mDetailsPresenter.onViewAttachedToWindow(
    588                     ((ViewHolder) vh).mDetailsDescriptionViewHolder);
    589         }
    590     }
    591 
    592     @Override
    593     protected void onRowViewDetachedFromWindow(RowPresenter.ViewHolder vh) {
    594         super.onRowViewDetachedFromWindow(vh);
    595         if (mDetailsPresenter != null) {
    596             mDetailsPresenter.onViewDetachedFromWindow(
    597                     ((ViewHolder) vh).mDetailsDescriptionViewHolder);
    598         }
    599     }
    600 }
    601