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