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