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