/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package android.support.v17.leanback.widget;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.support.annotation.ColorInt;
import android.support.v17.leanback.R;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* A presenter for a control bar that supports "more actions",
* and toggling the set of controls between primary and secondary
* sets of {@link Actions}.
*/
class PlaybackControlsPresenter extends ControlBarPresenter {
/**
* The data type expected by this presenter.
*/
static class BoundData extends ControlBarPresenter.BoundData {
/**
* The adapter containing secondary actions.
*/
ObjectAdapter secondaryActionsAdapter;
}
class ViewHolder extends ControlBarPresenter.ViewHolder {
ObjectAdapter mMoreActionsAdapter;
ObjectAdapter.DataObserver mMoreActionsObserver;
final FrameLayout mMoreActionsDock;
Presenter.ViewHolder mMoreActionsViewHolder;
boolean mMoreActionsShowing;
final TextView mCurrentTime;
final TextView mTotalTime;
final ProgressBar mProgressBar;
int mCurrentTimeInSeconds;
StringBuilder mTotalTimeStringBuilder = new StringBuilder();
StringBuilder mCurrentTimeStringBuilder = new StringBuilder();
int mCurrentTimeMarginStart;
int mTotalTimeMarginEnd;
final PersistentFocusWrapper mControlsFocusWrapper;
ViewHolder(View rootView) {
super(rootView);
mMoreActionsDock = (FrameLayout) rootView.findViewById(R.id.more_actions_dock);
mCurrentTime = (TextView) rootView.findViewById(R.id.current_time);
mTotalTime = (TextView) rootView.findViewById(R.id.total_time);
mProgressBar = (ProgressBar) rootView.findViewById(R.id.playback_progress);
mMoreActionsObserver = new ObjectAdapter.DataObserver() {
@Override
public void onChanged() {
if (mMoreActionsShowing) {
showControls(mPresenter);
}
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
if (mMoreActionsShowing) {
for (int i = 0; i < itemCount; i++) {
bindControlToAction(positionStart + i, mPresenter);
}
}
}
};
mCurrentTimeMarginStart =
((MarginLayoutParams) mCurrentTime.getLayoutParams()).getMarginStart();
mTotalTimeMarginEnd =
((MarginLayoutParams) mTotalTime.getLayoutParams()).getMarginEnd();
mControlsFocusWrapper = (PersistentFocusWrapper) mControlBar.getParent();
}
void showMoreActions(boolean show) {
if (show) {
if (mMoreActionsViewHolder == null) {
Action action = new PlaybackControlsRow.MoreActions(mMoreActionsDock.getContext());
mMoreActionsViewHolder = mPresenter.onCreateViewHolder(mMoreActionsDock);
mPresenter.onBindViewHolder(mMoreActionsViewHolder, action);
mPresenter.setOnClickListener(mMoreActionsViewHolder, new View.OnClickListener() {
@Override
public void onClick(View v) {
toggleMoreActions();
}
});
}
if (mMoreActionsViewHolder.view.getParent() == null) {
mMoreActionsDock.addView(mMoreActionsViewHolder.view);
}
} else if (mMoreActionsViewHolder != null &&
mMoreActionsViewHolder.view.getParent() != null) {
mMoreActionsDock.removeView(mMoreActionsViewHolder.view);
}
}
void toggleMoreActions() {
mMoreActionsShowing = !mMoreActionsShowing;
showControls(mPresenter);
}
@Override
ObjectAdapter getDisplayedAdapter() {
return mMoreActionsShowing ? mMoreActionsAdapter : mAdapter;
}
@Override
int getChildMarginFromCenter(Context context, int numControls) {
int margin = getControlIconWidth(context);
if (numControls < 4) {
margin += getChildMarginBiggest(context);
} else if (numControls < 6) {
margin += getChildMarginBigger(context);
} else {
margin += getChildMarginDefault(context);
}
return margin;
}
void setTotalTime(int totalTimeMs) {
if (totalTimeMs <= 0) {
mTotalTime.setVisibility(View.GONE);
mProgressBar.setVisibility(View.GONE);
} else {
mTotalTime.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.VISIBLE);
formatTime(totalTimeMs / 1000, mTotalTimeStringBuilder);
mTotalTime.setText(mTotalTimeStringBuilder.toString());
mProgressBar.setMax(totalTimeMs);
}
}
int getTotalTime() {
return mProgressBar.getMax();
}
void setCurrentTime(int currentTimeMs) {
int seconds = currentTimeMs / 1000;
if (seconds != mCurrentTimeInSeconds) {
mCurrentTimeInSeconds = seconds;
formatTime(mCurrentTimeInSeconds, mCurrentTimeStringBuilder);
mCurrentTime.setText(mCurrentTimeStringBuilder.toString());
}
mProgressBar.setProgress(currentTimeMs);
}
int getCurrentTime() {
return mProgressBar.getProgress();
}
void setSecondaryProgress(int progressMs) {
mProgressBar.setSecondaryProgress(progressMs);
}
int getSecondaryProgress() {
return mProgressBar.getSecondaryProgress();
}
}
private static void formatTime(int seconds, StringBuilder sb) {
int minutes = seconds / 60;
int hours = minutes / 60;
seconds -= minutes * 60;
minutes -= hours * 60;
sb.setLength(0);
if (hours > 0) {
sb.append(hours).append(':');
if (minutes < 10) {
sb.append('0');
}
}
sb.append(minutes).append(':');
if (seconds < 10) {
sb.append('0');
}
sb.append(seconds);
}
private boolean mMoreActionsEnabled = true;
private static int sChildMarginBigger;
private static int sChildMarginBiggest;
/**
* Constructor for a PlaybackControlsRowPresenter.
*
* @param layoutResourceId The resource id of the layout for this presenter.
*/
public PlaybackControlsPresenter(int layoutResourceId) {
super(layoutResourceId);
}
/**
* Enables the display of secondary actions.
* A "more actions" button will be displayed. When "more actions" is selected,
* the primary actions are replaced with the secondary actions.
*/
public void enableSecondaryActions(boolean enable) {
mMoreActionsEnabled = enable;
}
/**
* Returns true if secondary actions are enabled.
*/
public boolean areMoreActionsEnabled() {
return mMoreActionsEnabled;
}
public void setProgressColor(ViewHolder vh, @ColorInt int color) {
Drawable drawable = new ClipDrawable(new ColorDrawable(color),
Gravity.LEFT, ClipDrawable.HORIZONTAL);
((LayerDrawable) vh.mProgressBar.getProgressDrawable())
.setDrawableByLayerId(android.R.id.progress, drawable);
}
public void setTotalTime(ViewHolder vh, int ms) {
vh.setTotalTime(ms);
}
public int getTotalTime(ViewHolder vh) {
return vh.getTotalTime();
}
public void setCurrentTime(ViewHolder vh, int ms) {
vh.setCurrentTime(ms);
}
public int getCurrentTime(ViewHolder vh) {
return vh.getCurrentTime();
}
public void setSecondaryProgress(ViewHolder vh, int progressMs) {
vh.setSecondaryProgress(progressMs);
}
public int getSecondaryProgress(ViewHolder vh) {
return vh.getSecondaryProgress();
}
public void showPrimaryActions(ViewHolder vh) {
if (vh.mMoreActionsShowing) {
vh.toggleMoreActions();
}
}
public void resetFocus(ViewHolder vh) {
vh.mControlsFocusWrapper.clearSelection();
vh.mControlBar.requestFocus();
}
public void enableTimeMargins(ViewHolder vh, boolean enable) {
MarginLayoutParams lp;
lp = (MarginLayoutParams) vh.mCurrentTime.getLayoutParams();
lp.setMarginStart(enable ? vh.mCurrentTimeMarginStart : 0);
vh.mCurrentTime.setLayoutParams(lp);
lp = (MarginLayoutParams) vh.mTotalTime.getLayoutParams();
lp.setMarginEnd(enable ? vh.mTotalTimeMarginEnd : 0);
vh.mTotalTime.setLayoutParams(lp);
}
@Override
public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) {
View v = LayoutInflater.from(parent.getContext())
.inflate(getLayoutResourceId(), parent, false);
return new ViewHolder(v);
}
@Override
public void onBindViewHolder(Presenter.ViewHolder holder, Object item) {
ViewHolder vh = (ViewHolder) holder;
BoundData data = (BoundData) item;
// If binding to a new adapter, display primary actions.
if (vh.mMoreActionsAdapter != data.secondaryActionsAdapter) {
vh.mMoreActionsAdapter = data.secondaryActionsAdapter;
vh.mMoreActionsAdapter.registerObserver(vh.mMoreActionsObserver);
vh.mMoreActionsShowing = false;
}
super.onBindViewHolder(holder, item);
vh.showMoreActions(mMoreActionsEnabled);
}
@Override
public void onUnbindViewHolder(Presenter.ViewHolder holder) {
super.onUnbindViewHolder(holder);
ViewHolder vh = (ViewHolder) holder;
if (vh.mMoreActionsAdapter != null) {
vh.mMoreActionsAdapter.unregisterObserver(vh.mMoreActionsObserver);
vh.mMoreActionsAdapter = null;
}
}
int getChildMarginBigger(Context context) {
if (sChildMarginBigger == 0) {
sChildMarginBigger = context.getResources().getDimensionPixelSize(
R.dimen.lb_playback_controls_child_margin_bigger);
}
return sChildMarginBigger;
}
int getChildMarginBiggest(Context context) {
if (sChildMarginBiggest == 0) {
sChildMarginBiggest = context.getResources().getDimensionPixelSize(
R.dimen.lb_playback_controls_child_margin_biggest);
}
return sChildMarginBiggest;
}
}