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