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