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