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