| /* |
| * 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 = -1; |
| 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(); |
| } |
| } |
| |
| 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; |
| } |
| } |