PlaybackControlsRowPresenter.java revision cf992de2d34abb8228dc6cb39fffe97346823a37
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 */ 14package android.support.v17.leanback.widget; 15 16import android.support.v17.leanback.R; 17import android.support.v17.leanback.widget.ControlBarPresenter.OnControlClickedListener; 18import android.support.v17.leanback.widget.ControlBarPresenter.OnControlSelectedListener; 19import android.content.Context; 20import android.graphics.Color; 21import android.util.TypedValue; 22import android.view.LayoutInflater; 23import android.view.View; 24import android.view.ViewGroup; 25import android.view.ViewGroup.LayoutParams; 26import android.view.ViewGroup.MarginLayoutParams; 27import android.widget.ImageView; 28 29/** 30 * A PlaybackControlsRowPresenter renders a {@link PlaybackControlsRow} to display a 31 * series of playback control buttons. Typically this row will be the first row in a fragment 32 * such as the {@link android.support.v17.leanback.app.PlaybackOverlayFragment 33 * PlaybackControlsFragment}. 34 */ 35public class PlaybackControlsRowPresenter extends RowPresenter { 36 37 static class BoundData extends PlaybackControlsPresenter.BoundData { 38 ViewHolder mRowViewHolder; 39 } 40 41 /** 42 * A ViewHolder for the PlaybackControlsRow. 43 */ 44 public class ViewHolder extends RowPresenter.ViewHolder { 45 public final Presenter.ViewHolder mDescriptionViewHolder; 46 final ViewGroup mCard; 47 final ImageView mImageView; 48 final ViewGroup mDescriptionDock; 49 final ViewGroup mControlsDock; 50 final ViewGroup mSecondaryControlsDock; 51 final View mSpacer; 52 final View mBottomSpacer; 53 View mBgView; 54 int mCardHeight; 55 int mControlsDockMarginStart; 56 int mControlsDockMarginEnd; 57 PlaybackControlsPresenter.ViewHolder mControlsVh; 58 Presenter.ViewHolder mSecondaryControlsVh; 59 BoundData mControlsBoundData = new BoundData(); 60 BoundData mSecondaryBoundData = new BoundData(); 61 Presenter.ViewHolder mSelectedViewHolder; 62 Object mSelectedItem; 63 final PlaybackControlsRow.OnPlaybackStateChangedListener mListener = 64 new PlaybackControlsRow.OnPlaybackStateChangedListener() { 65 @Override 66 public void onCurrentTimeChanged(int ms) { 67 mPlaybackControlsPresenter.setCurrentTime(mControlsVh, ms); 68 } 69 @Override 70 public void onBufferedProgressChanged(int ms) { 71 mPlaybackControlsPresenter.setSecondaryProgress(mControlsVh, ms); 72 } 73 }; 74 75 ViewHolder(View rootView, Presenter descriptionPresenter) { 76 super(rootView); 77 mCard = (ViewGroup) rootView.findViewById(R.id.controls_card); 78 mImageView = (ImageView) rootView.findViewById(R.id.image); 79 mDescriptionDock = (ViewGroup) rootView.findViewById(R.id.description_dock); 80 mControlsDock = (ViewGroup) rootView.findViewById(R.id.controls_dock); 81 mSecondaryControlsDock = 82 (ViewGroup) rootView.findViewById(R.id.secondary_controls_dock); 83 mSpacer = rootView.findViewById(R.id.spacer); 84 mBottomSpacer = rootView.findViewById(R.id.bottom_spacer); 85 mDescriptionViewHolder = descriptionPresenter == null ? null : 86 descriptionPresenter.onCreateViewHolder(mDescriptionDock); 87 if (mDescriptionViewHolder != null) { 88 mDescriptionDock.addView(mDescriptionViewHolder.view); 89 } 90 } 91 92 void dispatchItemSelection() { 93 if (!isSelected()) { 94 return; 95 } 96 if (mSelectedViewHolder == null) { 97 if (getOnItemSelectedListener() != null) { 98 getOnItemSelectedListener().onItemSelected(null, getRow()); 99 } 100 if (getOnItemViewSelectedListener() != null) { 101 getOnItemViewSelectedListener().onItemSelected(null, null, 102 ViewHolder.this, getRow()); 103 } 104 } else { 105 if (getOnItemSelectedListener() != null) { 106 getOnItemSelectedListener().onItemSelected(mSelectedItem, getRow()); 107 } 108 if (getOnItemViewSelectedListener() != null) { 109 getOnItemViewSelectedListener().onItemSelected(mSelectedViewHolder, mSelectedItem, 110 ViewHolder.this, getRow()); 111 } 112 } 113 }; 114 115 Presenter getPresenter(boolean primary) { 116 ObjectAdapter adapter = primary ? 117 ((PlaybackControlsRow) getRow()).getPrimaryActionsAdapter() : 118 ((PlaybackControlsRow) getRow()).getSecondaryActionsAdapter(); 119 if (adapter.getPresenterSelector() instanceof ControlButtonPresenterSelector) { 120 ControlButtonPresenterSelector selector = 121 (ControlButtonPresenterSelector) adapter.getPresenterSelector(); 122 return primary ? selector.getPrimaryPresenter() : 123 selector.getSecondaryPresenter(); 124 } 125 return adapter.getPresenter(adapter.size() > 0 ? adapter.get(0) : null); 126 } 127 128 void setBackground(View view) { 129 if (mBgView != null) { 130 RoundedRectHelper.getInstance().clearBackground(mBgView); 131 ShadowHelper.getInstance().clearZ(mBgView); 132 } 133 mBgView = view; 134 RoundedRectHelper.getInstance().setRoundedRectBackground(view, mBackgroundColorSet ? 135 mBackgroundColor : getDefaultBackgroundColor(view.getContext())); 136 ShadowHelper.getInstance().setZ(view, 0f); 137 } 138 } 139 140 private int mBackgroundColor = Color.TRANSPARENT; 141 private boolean mBackgroundColorSet; 142 private int mProgressColor = Color.TRANSPARENT; 143 private boolean mProgressColorSet; 144 private boolean mSecondaryActionsHidden; 145 private Presenter mDescriptionPresenter; 146 private PlaybackControlsPresenter mPlaybackControlsPresenter; 147 private ControlBarPresenter mSecondaryControlsPresenter; 148 private OnActionClickedListener mOnActionClickedListener; 149 150 private final OnControlSelectedListener mOnControlSelectedListener = 151 new OnControlSelectedListener() { 152 @Override 153 public void onControlSelected(Presenter.ViewHolder itemViewHolder, Object item, 154 ControlBarPresenter.BoundData data) { 155 ViewHolder vh = ((BoundData) data).mRowViewHolder; 156 if (vh.mSelectedViewHolder != itemViewHolder || vh.mSelectedItem != item) { 157 vh.mSelectedViewHolder = itemViewHolder; 158 vh.mSelectedItem = item; 159 vh.dispatchItemSelection(); 160 } 161 } 162 }; 163 164 private final OnControlClickedListener mOnControlClickedListener = 165 new OnControlClickedListener() { 166 @Override 167 public void onControlClicked(Presenter.ViewHolder itemViewHolder, Object item, 168 ControlBarPresenter.BoundData data) { 169 ViewHolder vh = ((BoundData) data).mRowViewHolder; 170 if (getOnItemClickedListener() != null) { 171 getOnItemClickedListener().onItemClicked(item, vh.getRow()); 172 } 173 if (getOnItemViewClickedListener() != null) { 174 getOnItemViewClickedListener().onItemClicked(itemViewHolder, item, 175 vh, vh.getRow()); 176 } 177 if (mOnActionClickedListener != null && item instanceof Action) { 178 mOnActionClickedListener.onActionClicked((Action) item); 179 } 180 } 181 }; 182 183 /** 184 * Constructor for a PlaybackControlsRowPresenter. 185 * 186 * @param descriptionPresenter Presenter for displaying item details. 187 */ 188 public PlaybackControlsRowPresenter(Presenter descriptionPresenter) { 189 setHeaderPresenter(null); 190 setSelectEffectEnabled(false); 191 192 mDescriptionPresenter = descriptionPresenter; 193 mPlaybackControlsPresenter = new PlaybackControlsPresenter(R.layout.lb_playback_controls); 194 mSecondaryControlsPresenter = new ControlBarPresenter(R.layout.lb_control_bar); 195 196 mPlaybackControlsPresenter.setOnControlSelectedListener(mOnControlSelectedListener); 197 mSecondaryControlsPresenter.setOnControlSelectedListener(mOnControlSelectedListener); 198 mPlaybackControlsPresenter.setOnControlClickedListener(mOnControlClickedListener); 199 mSecondaryControlsPresenter.setOnControlClickedListener(mOnControlClickedListener); 200 } 201 202 /** 203 * Constructor for a PlaybackControlsRowPresenter. 204 */ 205 public PlaybackControlsRowPresenter() { 206 this(null); 207 } 208 209 /** 210 * Sets the listener for {@link Action} click events. 211 */ 212 public void setOnActionClickedListener(OnActionClickedListener listener) { 213 mOnActionClickedListener = listener; 214 } 215 216 /** 217 * Gets the listener for {@link Action} click events. 218 */ 219 public OnActionClickedListener getOnActionClickedListener() { 220 return mOnActionClickedListener; 221 } 222 223 /** 224 * Sets the background color. If not set, a default from the theme will be used. 225 */ 226 public void setBackgroundColor(int color) { 227 mBackgroundColor = color; 228 mBackgroundColorSet = true; 229 } 230 231 /** 232 * Returns the background color. If no background color was set, transparent 233 * is returned. 234 */ 235 public int getBackgroundColor() { 236 return mBackgroundColor; 237 } 238 239 /** 240 * Sets the primary color for the progress bar. If not set, a default from 241 * the theme will be used. 242 */ 243 public void setProgressColor(int color) { 244 mProgressColor = color; 245 mProgressColorSet = true; 246 } 247 248 /** 249 * Returns the primary color for the progress bar. If no color was set, transparent 250 * is returned. 251 */ 252 public int getProgressColor() { 253 return mProgressColor; 254 } 255 256 /** 257 * Sets the secondary actions to be hidden behind a "more actions" button. 258 * When "more actions" is selected, the primary actions are replaced with 259 * the secondary actions. 260 */ 261 public void setSecondaryActionsHidden(boolean hidden) { 262 mSecondaryActionsHidden = hidden; 263 } 264 265 /** 266 * Returns true if secondary actions are hidden. 267 */ 268 public boolean areSecondaryActionsHidden() { 269 return mSecondaryActionsHidden; 270 } 271 272 /** 273 * Shows or hides space at the bottom of the playback controls row. 274 * This allows the row to hug the bottom of the display when no 275 * other rows are present. 276 */ 277 public void showBottomSpace(ViewHolder vh, boolean show) { 278 vh.mBottomSpacer.setVisibility(show ? View.VISIBLE : View.GONE); 279 } 280 281 /** 282 * Display the primary actions. 283 */ 284 public void showPrimaryActions(ViewHolder vh) { 285 mPlaybackControlsPresenter.showPrimaryActions(vh.mControlsVh); 286 } 287 288 private int getDefaultBackgroundColor(Context context) { 289 TypedValue outValue = new TypedValue(); 290 context.getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true); 291 return context.getResources().getColor(outValue.resourceId); 292 } 293 294 private int getDefaultProgressColor(Context context) { 295 TypedValue outValue = new TypedValue(); 296 context.getTheme().resolveAttribute(R.attr.playbackProgressPrimaryColor, outValue, true); 297 return context.getResources().getColor(outValue.resourceId); 298 } 299 300 @Override 301 protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) { 302 View v = LayoutInflater.from(parent.getContext()) 303 .inflate(R.layout.lb_playback_controls_row, parent, false); 304 ViewHolder vh = new ViewHolder(v, mDescriptionPresenter); 305 initRow(vh); 306 return vh; 307 } 308 309 private void initRow(ViewHolder vh) { 310 vh.mCardHeight = vh.mCard.getLayoutParams().height; 311 312 MarginLayoutParams lp = (MarginLayoutParams) vh.mControlsDock.getLayoutParams(); 313 vh.mControlsDockMarginStart = lp.getMarginStart(); 314 vh.mControlsDockMarginEnd = lp.getMarginEnd(); 315 316 vh.mControlsVh = (PlaybackControlsPresenter.ViewHolder) 317 mPlaybackControlsPresenter.onCreateViewHolder(vh.mControlsDock); 318 mPlaybackControlsPresenter.setProgressColor(vh.mControlsVh, 319 mProgressColorSet ? mProgressColor : 320 getDefaultProgressColor(vh.mControlsDock.getContext())); 321 vh.mControlsDock.addView(vh.mControlsVh.view); 322 323 vh.mSecondaryControlsVh = 324 mSecondaryControlsPresenter.onCreateViewHolder(vh.mSecondaryControlsDock); 325 if (!mSecondaryActionsHidden) { 326 vh.mSecondaryControlsDock.addView(vh.mSecondaryControlsVh.view); 327 } 328 } 329 330 @Override 331 protected void onBindRowViewHolder(RowPresenter.ViewHolder holder, Object item) { 332 super.onBindRowViewHolder(holder, item); 333 334 ViewHolder vh = (ViewHolder) holder; 335 PlaybackControlsRow row = (PlaybackControlsRow) vh.getRow(); 336 337 mPlaybackControlsPresenter.enableSecondaryActions(mSecondaryActionsHidden); 338 339 if (row.getItem() == null) { 340 LayoutParams lp = vh.mCard.getLayoutParams(); 341 lp.height = LayoutParams.WRAP_CONTENT; 342 vh.mCard.setLayoutParams(lp); 343 vh.mDescriptionDock.setVisibility(View.GONE); 344 vh.mSpacer.setVisibility(View.GONE); 345 } else { 346 LayoutParams lp = vh.mCard.getLayoutParams(); 347 lp.height = vh.mCardHeight; 348 vh.mCard.setLayoutParams(lp); 349 vh.mDescriptionDock.setVisibility(View.VISIBLE); 350 if (vh.mDescriptionViewHolder != null) { 351 mDescriptionPresenter.onBindViewHolder(vh.mDescriptionViewHolder, row.getItem()); 352 } 353 vh.mSpacer.setVisibility(View.VISIBLE); 354 } 355 356 MarginLayoutParams lp = (MarginLayoutParams) vh.mControlsDock.getLayoutParams(); 357 if (row.getImageDrawable() == null || row.getItem() == null) { 358 vh.setBackground(vh.mControlsDock); 359 lp.setMarginStart(0); 360 lp.setMarginEnd(0); 361 mPlaybackControlsPresenter.enableTimeMargins(vh.mControlsVh, true); 362 } else { 363 vh.mImageView.setImageDrawable(row.getImageDrawable()); 364 vh.setBackground(vh.mCard); 365 lp.setMarginStart(vh.mControlsDockMarginStart); 366 lp.setMarginEnd(vh.mControlsDockMarginEnd); 367 mPlaybackControlsPresenter.enableTimeMargins(vh.mControlsVh, false); 368 } 369 vh.mControlsDock.setLayoutParams(lp); 370 371 vh.mControlsBoundData.adapter = row.getPrimaryActionsAdapter(); 372 vh.mControlsBoundData.secondaryActionsAdapter = row.getSecondaryActionsAdapter(); 373 vh.mControlsBoundData.presenter = vh.getPresenter(true); 374 vh.mControlsBoundData.mRowViewHolder = vh; 375 mPlaybackControlsPresenter.onBindViewHolder(vh.mControlsVh, vh.mControlsBoundData); 376 377 vh.mSecondaryBoundData.adapter = row.getSecondaryActionsAdapter(); 378 vh.mSecondaryBoundData.presenter = vh.getPresenter(false); 379 vh.mSecondaryBoundData.mRowViewHolder = vh; 380 mSecondaryControlsPresenter.onBindViewHolder(vh.mSecondaryControlsVh, 381 vh.mSecondaryBoundData); 382 383 mPlaybackControlsPresenter.setTotalTime(vh.mControlsVh, row.getTotalTime()); 384 mPlaybackControlsPresenter.setCurrentTime(vh.mControlsVh, row.getCurrentTime()); 385 mPlaybackControlsPresenter.setSecondaryProgress(vh.mControlsVh, row.getBufferedProgress()); 386 row.setOnPlaybackStateChangedListener(vh.mListener); 387 } 388 389 @Override 390 protected void onUnbindRowViewHolder(RowPresenter.ViewHolder holder) { 391 ViewHolder vh = (ViewHolder) holder; 392 PlaybackControlsRow row = (PlaybackControlsRow) vh.getRow(); 393 394 if (vh.mDescriptionViewHolder != null) { 395 mDescriptionPresenter.onUnbindViewHolder(vh.mDescriptionViewHolder); 396 } 397 mPlaybackControlsPresenter.onUnbindViewHolder(vh.mControlsVh); 398 mSecondaryControlsPresenter.onUnbindViewHolder(vh.mSecondaryControlsVh); 399 row.setOnPlaybackStateChangedListener(null); 400 401 super.onUnbindRowViewHolder(holder); 402 } 403 404 protected void onRowViewSelected(RowPresenter.ViewHolder vh, boolean selected) { 405 super.onRowViewSelected(vh, selected); 406 if (selected) { 407 ((ViewHolder) vh).dispatchItemSelection(); 408 } 409 } 410} 411