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 ActionsItemBridgeAdapter(DetailsOverviewRowPresenter.ViewHolder viewHolder)74 ActionsItemBridgeAdapter(DetailsOverviewRowPresenter.ViewHolder viewHolder) { 75 mViewHolder = viewHolder; 76 } 77 78 @Override onBind(final ItemBridgeAdapter.ViewHolder ibvh)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 onUnbind(final ItemBridgeAdapter.ViewHolder ibvh)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 onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder)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 onDetachedFromWindow(ItemBridgeAdapter.ViewHolder viewHolder)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 bindActions(ObjectAdapter adapter)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 dispatchItemSelection(View view)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 getViewCenter(View view)223 private int getViewCenter(View view) { 224 return (view.getRight() - view.getLeft()) / 2; 225 } 226 checkFirstAndLastPosition(boolean fromScroll)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 showMoreLeft(boolean show)246 private void showMoreLeft(boolean show) { 247 if (show != mShowMoreLeft) { 248 mActionsRow.setFadingLeftEdge(show); 249 mShowMoreLeft = show; 250 } 251 } 252 showMoreRight(boolean show)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 */ ViewHolder(View rootView, Presenter detailsPresenter)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 */ DetailsOverviewRowPresenter(Presenter detailsPresenter)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 */ setOnActionClickedListener(OnActionClickedListener listener)315 public void setOnActionClickedListener(OnActionClickedListener listener) { 316 mActionClickedListener = listener; 317 } 318 319 /** 320 * Returns the listener for Action click events. 321 */ getOnActionClickedListener()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 */ setBackgroundColor(@olorInt int color)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 getBackgroundColor()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 */ setStyleLarge(boolean large)347 public void setStyleLarge(boolean large) { 348 mIsStyleLarge = large; 349 } 350 351 /** 352 * Returns true if the layout style is large. 353 */ isStyleLarge()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 */ setSharedElementEnterTransition(Activity activity, String sharedElementName, long timeoutMs)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 */ setSharedElementEnterTransition(Activity activity, String sharedElementName)391 public final void setSharedElementEnterTransition(Activity activity, 392 String sharedElementName) { 393 setSharedElementEnterTransition(activity, sharedElementName, DEFAULT_TIMEOUT); 394 } 395 getDefaultBackgroundColor(Context context)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 onRowViewSelected(RowPresenter.ViewHolder vh, boolean selected)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 createRowViewHolder(ViewGroup parent)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 getCardHeight(Context context)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 initDetailsOverview(final ViewHolder vh)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 getNonNegativeWidth(Drawable drawable)452 private static int getNonNegativeWidth(Drawable drawable) { 453 final int width = (drawable == null) ? 0 : drawable.getIntrinsicWidth(); 454 return (width > 0 ? width : 0); 455 } 456 getNonNegativeHeight(Drawable drawable)457 private static int getNonNegativeHeight(Drawable drawable) { 458 final int height = (drawable == null) ? 0 : drawable.getIntrinsicHeight(); 459 return (height > 0 ? height : 0); 460 } 461 bindImageDrawable(ViewHolder vh)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 onBindRowViewHolder(RowPresenter.ViewHolder holder, Object item)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 onUnbindRowViewHolder(RowPresenter.ViewHolder holder)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 isUsingDefaultSelectEffect()569 public final boolean isUsingDefaultSelectEffect() { 570 return false; 571 } 572 573 @Override onSelectLevelChanged(RowPresenter.ViewHolder holder)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 onRowViewAttachedToWindow(RowPresenter.ViewHolder vh)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 onRowViewDetachedFromWindow(RowPresenter.ViewHolder vh)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