PlaybackControlsPresenter.java revision e5b67be786d519377ae275ef76f3ad72187183d5
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.animation.ValueAnimator;
17import android.graphics.drawable.ClipDrawable;
18import android.graphics.drawable.ColorDrawable;
19import android.graphics.drawable.Drawable;
20import android.graphics.drawable.LayerDrawable;
21import android.support.v17.leanback.R;
22import android.view.Gravity;
23import android.view.LayoutInflater;
24import android.view.View;
25import android.view.ViewGroup;
26import android.view.ViewGroup.MarginLayoutParams;
27import android.view.animation.LinearInterpolator;
28import android.widget.FrameLayout;
29import android.widget.ProgressBar;
30import android.widget.TextView;
31
32/**
33 * A presenter for a control bar that supports "more actions",
34 * and toggling the set of controls between primary and secondary
35 * sets of {@link Actions}.
36 */
37class PlaybackControlsPresenter extends ControlBarPresenter {
38
39    /**
40     * The data type expected by this presenter.
41     */
42    static class BoundData extends ControlBarPresenter.BoundData {
43        /**
44         * The adapter containing secondary actions.
45         */
46        ObjectAdapter secondaryActionsAdapter;
47    }
48
49    class ViewHolder extends ControlBarPresenter.ViewHolder {
50        ObjectAdapter mMoreActionsAdapter;
51        ObjectAdapter.DataObserver mMoreActionsObserver;
52        final FrameLayout mMoreActionsDock;
53        Presenter.ViewHolder mMoreActionsViewHolder;
54        boolean mMoreActionsShowing;
55        final TextView mCurrentTime;
56        final TextView mTotalTime;
57        final ProgressBar mProgressBar;
58        int mCurrentTimeInSeconds;
59        StringBuilder mTotalTimeStringBuilder = new StringBuilder();
60        StringBuilder mCurrentTimeStringBuilder = new StringBuilder();
61        int mCurrentTimeMarginStart;
62        int mTotalTimeMarginEnd;
63
64        ViewHolder(View rootView) {
65            super(rootView);
66            mMoreActionsDock = (FrameLayout) rootView.findViewById(R.id.more_actions_dock);
67            mCurrentTime = (TextView) rootView.findViewById(R.id.current_time);
68            mTotalTime = (TextView) rootView.findViewById(R.id.total_time);
69            mProgressBar = (ProgressBar) rootView.findViewById(R.id.playback_progress);
70            mMoreActionsObserver = new ObjectAdapter.DataObserver() {
71                @Override
72                public void onChanged() {
73                    if (mMoreActionsShowing) {
74                        showControls(mMoreActionsAdapter, mPresenter);
75                    }
76                }
77                @Override
78                public void onItemRangeChanged(int positionStart, int itemCount) {
79                    if (mMoreActionsShowing) {
80                        for (int i = 0; i < itemCount; i++) {
81                            bindControlToAction(positionStart + i,
82                                    mMoreActionsAdapter, mPresenter);
83                        }
84                    }
85                }
86            };
87            mCurrentTimeMarginStart =
88                    ((MarginLayoutParams) mCurrentTime.getLayoutParams()).getMarginStart();
89            mTotalTimeMarginEnd =
90                    ((MarginLayoutParams) mTotalTime.getLayoutParams()).getMarginEnd();
91        }
92
93        void showMoreActions() {
94            if (mMoreActionsViewHolder == null) {
95                Action action = new PlaybackControlsRow.MoreActions(mMoreActionsDock.getContext());
96                mMoreActionsViewHolder = mPresenter.onCreateViewHolder(mMoreActionsDock);
97                mPresenter.onBindViewHolder(mMoreActionsViewHolder, action);
98                mPresenter.setOnClickListener(mMoreActionsViewHolder, new View.OnClickListener() {
99                    @Override
100                    public void onClick(View v) {
101                        toggleMoreActions();
102                    }
103                });
104            }
105            mMoreActionsDock.addView(mMoreActionsViewHolder.view);
106        }
107
108        void toggleMoreActions() {
109            mMoreActionsShowing = !mMoreActionsShowing;
110            showControls(getAdapter(), mPresenter);
111        }
112
113        @Override
114        ObjectAdapter getAdapter() {
115            return mMoreActionsShowing ? mMoreActionsAdapter : mAdapter;
116        }
117
118        void setTotalTime(int totalTimeMs) {
119            if (totalTimeMs <= 0) {
120                mTotalTime.setVisibility(View.GONE);
121                mProgressBar.setVisibility(View.GONE);
122            } else {
123                mTotalTime.setVisibility(View.VISIBLE);
124                mProgressBar.setVisibility(View.VISIBLE);
125                formatTime(totalTimeMs / 1000, mTotalTimeStringBuilder);
126                mTotalTime.setText(mTotalTimeStringBuilder.toString());
127                mProgressBar.setMax(totalTimeMs);
128            }
129        }
130
131        int getTotalTime() {
132            return mProgressBar.getMax();
133        }
134
135        void setCurrentTime(int currentTimeMs) {
136            int seconds = currentTimeMs / 1000;
137            if (seconds != mCurrentTimeInSeconds) {
138                mCurrentTimeInSeconds = seconds;
139                formatTime(mCurrentTimeInSeconds, mCurrentTimeStringBuilder);
140                mCurrentTime.setText(mCurrentTimeStringBuilder.toString());
141            }
142            mProgressBar.setProgress(currentTimeMs);
143        }
144
145        int getCurrentTime() {
146            return mProgressBar.getProgress();
147        }
148
149        void setSecondaryProgress(int progressMs) {
150            mProgressBar.setSecondaryProgress(progressMs);
151        }
152
153        int getSecondaryProgress() {
154            return mProgressBar.getSecondaryProgress();
155        }
156    }
157
158    private static void formatTime(int seconds, StringBuilder sb) {
159        int minutes = seconds / 60;
160        int hours = minutes / 60;
161        seconds -= minutes * 60;
162        minutes -= hours * 60;
163
164        sb.setLength(0);
165        if (hours > 0) {
166            sb.append(hours).append(':');
167            if (minutes < 10) {
168                sb.append('0');
169            }
170        }
171        sb.append(minutes).append(':');
172        if (seconds < 10) {
173            sb.append('0');
174        }
175        sb.append(seconds);
176    }
177
178    private boolean mMoreActionsEnabled = true;
179
180    /**
181     * Constructor for a PlaybackControlsRowPresenter.
182     *
183     * @param layoutResourceId The resource id of the layout for this presenter.
184     */
185    public PlaybackControlsPresenter(int layoutResourceId) {
186        super(layoutResourceId);
187    }
188
189    /**
190     * Enables the display of secondary actions.
191     * A "more actions" button will be displayed.  When "more actions" is selected,
192     * the primary actions are replaced with the secondary actions.
193     */
194    public void enableSecondaryActions(boolean enable) {
195        mMoreActionsEnabled = enable;
196    }
197
198    /**
199     * Returns true if secondary actions are enabled.
200     */
201    public boolean areMoreActionsEnabled() {
202        return mMoreActionsEnabled;
203    }
204
205    public void setProgressColor(ViewHolder vh, int color) {
206        Drawable drawable = new ClipDrawable(new ColorDrawable(color),
207                Gravity.LEFT, ClipDrawable.HORIZONTAL);
208        ((LayerDrawable) vh.mProgressBar.getProgressDrawable())
209                .setDrawableByLayerId(android.R.id.progress, drawable);
210    }
211
212    public void setTotalTime(ViewHolder vh, int ms) {
213        vh.setTotalTime(ms);
214    }
215
216    public int getTotalTime(ViewHolder vh) {
217        return vh.getTotalTime();
218    }
219
220    public void setCurrentTime(ViewHolder vh, int ms) {
221        vh.setCurrentTime(ms);
222    }
223
224    public int getCurrentTime(ViewHolder vh) {
225        return vh.getCurrentTime();
226    }
227
228    public void setSecondaryProgress(ViewHolder vh, int progressMs) {
229        vh.setSecondaryProgress(progressMs);
230    }
231
232    public int getSecondaryProgress(ViewHolder vh) {
233        return vh.getSecondaryProgress();
234    }
235
236    public void enableTimeMargins(ViewHolder vh, boolean enable) {
237        MarginLayoutParams lp;
238        lp = (MarginLayoutParams) vh.mCurrentTime.getLayoutParams();
239        lp.setMarginStart(enable ? vh.mCurrentTimeMarginStart : 0);
240        vh.mCurrentTime.setLayoutParams(lp);
241
242        lp = (MarginLayoutParams) vh.mTotalTime.getLayoutParams();
243        lp.setMarginEnd(enable ? vh.mTotalTimeMarginEnd : 0);
244        vh.mTotalTime.setLayoutParams(lp);
245    }
246
247    @Override
248    public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) {
249        View v = LayoutInflater.from(parent.getContext())
250            .inflate(getLayoutResourceId(), parent, false);
251        return new ViewHolder(v);
252    }
253
254    @Override
255    public void onBindViewHolder(Presenter.ViewHolder holder, Object item) {
256        super.onBindViewHolder(holder, item);
257
258        ViewHolder vh = (ViewHolder) holder;
259        BoundData data = (BoundData) item;
260        if (vh.mMoreActionsAdapter != data.secondaryActionsAdapter) {
261            vh.mMoreActionsAdapter = data.secondaryActionsAdapter;
262            vh.mMoreActionsAdapter.registerObserver(vh.mMoreActionsObserver);
263        }
264        if (mMoreActionsEnabled) {
265            vh.showMoreActions();
266        }
267    }
268
269    @Override
270    public void onUnbindViewHolder(Presenter.ViewHolder holder) {
271        super.onUnbindViewHolder(holder);
272        ViewHolder vh = (ViewHolder) holder;
273        vh.mMoreActionsAdapter.unregisterObserver(vh.mMoreActionsObserver);
274        vh.mMoreActionsAdapter = null;
275    }
276}
277