blob: 190ce2285a57ad48534dd53144e2d71b5551d844 [file] [log] [blame]
/*
* Copyright (C) 2016 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.app;
import android.content.Context;
import android.support.v17.leanback.media.PlaybackGlueHost;
import android.support.v17.leanback.widget.Action;
import android.support.v17.leanback.widget.OnActionClickedListener;
import android.support.v17.leanback.widget.OnItemViewClickedListener;
import android.support.v17.leanback.widget.PlaybackControlsRow;
import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
import android.support.v17.leanback.widget.PlaybackRowPresenter;
import android.support.v17.leanback.widget.Presenter;
import android.support.v17.leanback.widget.PresenterSelector;
import android.support.v17.leanback.widget.Row;
import android.support.v17.leanback.widget.RowPresenter;
import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.View;
/**
* A helper class for managing a {@link android.support.v17.leanback.widget.PlaybackControlsRow}
* and {@link PlaybackGlueHost} that implements a
* recommended approach to handling standard playback control actions such as play/pause,
* fast forward/rewind at progressive speed levels, and skip to next/previous. This helper class
* is a glue layer in that manages the configuration of and interaction between the
* leanback UI components by defining a functional interface to the media player.
*
* <p>You can instantiate a concrete subclass such as MediaPlayerGlue or you must
* subclass this abstract helper. To create a subclass you must implement all of the
* abstract methods and the subclass must invoke {@link #onMetadataChanged()} and
* {@link #onStateChanged()} appropriately.
* </p>
*
* <p>To use an instance of the glue layer, first construct an instance. Constructor parameters
* inform the glue what speed levels are supported for fast forward/rewind.
* </p>
*
* <p>If you have your own controls row you must pass it to {@link #setControlsRow}.
* The row will be updated by the glue layer based on the media metadata and playback state.
* Alternatively, you may call {@link #createControlsRowAndPresenter()} which will set a controls
* row and return a row presenter you can use to present the row.
* </p>
*
* <p>The helper sets a {@link android.support.v17.leanback.widget.SparseArrayObjectAdapter}
* on the controls row as the primary actions adapter, and adds actions to it. You can provide
* additional actions by overriding {@link #createPrimaryActionsAdapter}. This helper does not
* deal in secondary actions so those you may add separately.
* </p>
*
* <p>Provide a click listener on your fragment and if an action is clicked, call
* {@link #onActionClicked}. If you set a listener by calling {@link #setOnItemViewClickedListener},
* your listener will be called for all unhandled actions.
* </p>
*
* <p>This helper implements a key event handler. If you pass a
* {@link PlaybackOverlayFragment}, it will configure it's
* fragment to intercept all key events. Otherwise, you should set the glue object as key event
* handler to the ViewHolder when bound by your row presenter; see
* {@link RowPresenter.ViewHolder#setOnKeyListener(android.view.View.OnKeyListener)}.
* </p>
*
* <p>To update the controls row progress during playback, override {@link #enableProgressUpdating}
* to manage the lifecycle of a periodic callback to {@link #updateProgress()}.
* {@link #getUpdatePeriod()} provides a recommended update period.
* </p>
* @deprecated Use {@link android.support.v17.leanback.media.PlaybackControlGlue}
*/
@Deprecated
public abstract class PlaybackControlGlue extends
android.support.v17.leanback.media.PlaybackControlGlue {
OnItemViewClickedListener mExternalOnItemViewClickedListener;
/**
* Constructor for the glue.
*
* @param context
* @param seekSpeeds Array of seek speeds for fast forward and rewind.
*/
public PlaybackControlGlue(Context context, int[] seekSpeeds) {
super(context, seekSpeeds, seekSpeeds);
}
/**
* Constructor for the glue.
*
* @param context
* @param fastForwardSpeeds Array of seek speeds for fast forward.
* @param rewindSpeeds Array of seek speeds for rewind.
*/
public PlaybackControlGlue(Context context,
int[] fastForwardSpeeds,
int[] rewindSpeeds) {
super(context, fastForwardSpeeds, rewindSpeeds);
}
/**
* Constructor for the glue.
*
* @param context
* @param fragment Optional; if using a {@link PlaybackOverlayFragment}, pass it in.
* @param seekSpeeds Array of seek speeds for fast forward and rewind.
*/
public PlaybackControlGlue(Context context,
PlaybackOverlayFragment fragment,
int[] seekSpeeds) {
this(context, fragment, seekSpeeds, seekSpeeds);
}
/**
* Constructor for the glue.
*
* @param context
* @param fragment Optional; if using a {@link PlaybackOverlayFragment}, pass it in.
* @param fastForwardSpeeds Array of seek speeds for fast forward.
* @param rewindSpeeds Array of seek speeds for rewind.
*/
public PlaybackControlGlue(Context context,
PlaybackOverlayFragment fragment,
int[] fastForwardSpeeds,
int[] rewindSpeeds) {
super(context, fastForwardSpeeds, rewindSpeeds);
setHost(fragment == null ? (PlaybackGlueHost) null : new PlaybackGlueHostOld(fragment));
}
@Override
protected void onAttachedToHost(PlaybackGlueHost host) {
super.onAttachedToHost(host);
if (host instanceof PlaybackGlueHostOld) {
((PlaybackGlueHostOld) host).mGlue = this;
}
}
/**
* Returns the fragment.
*/
public PlaybackOverlayFragment getFragment() {
if (getHost() instanceof PlaybackGlueHostOld) {
return ((PlaybackGlueHostOld)getHost()).mFragment;
}
return null;
}
/**
* Start playback at the given speed.
* @deprecated use {@link #play()} instead.
*
* @param speed The desired playback speed. For normal playback this will be
* {@link #PLAYBACK_SPEED_NORMAL}; higher positive values for fast forward,
* and negative values for rewind.
*/
@Deprecated
protected void startPlayback(int speed) {}
/**
* Pause playback.
* @deprecated use {@link #pause()} instead.
*/
@Deprecated
protected void pausePlayback() {}
/**
* Skip to the next track.
* @deprecated use {@link #next()} instead.
*/
@Deprecated
protected void skipToNext() {}
/**
* Skip to the previous track.
* @deprecated use {@link #previous()} instead.
*/
@Deprecated
protected void skipToPrevious() {}
@Override
public final void next() {
skipToNext();
}
@Override
public final void previous() {
skipToPrevious();
}
@Override
public final void play(int speed) {
startPlayback(speed);
}
@Override
public final void pause() {
pausePlayback();
}
/**
* This method invoked when the playback controls row has changed. The adapter
* containing this row should be notified.
*/
protected void onRowChanged(PlaybackControlsRow row) {
}
/**
* Set the {@link OnItemViewClickedListener} to be called if the click event
* is not handled internally.
* @param listener
* @deprecated Don't call this. Instead use the listener on the fragment yourself.
*/
@Deprecated
public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
mExternalOnItemViewClickedListener = listener;
}
/**
* Returns the {@link OnItemViewClickedListener}.
* @deprecated Don't call this. Instead use the listener on the fragment yourself.
*/
@Deprecated
public OnItemViewClickedListener getOnItemViewClickedListener() {
return mExternalOnItemViewClickedListener;
}
@Override
protected void onCreateControlsRowAndPresenter() {
// backward compatible, we dont create row / presenter by default.
// User is expected to call createControlsRowAndPresenter() or setControlsRow()
// explicitly.
}
/**
* Helper method for instantiating a
* {@link android.support.v17.leanback.widget.PlaybackControlsRow} and corresponding
* {@link android.support.v17.leanback.widget.PlaybackControlsRowPresenter}.
*/
public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
super.onCreateControlsRowAndPresenter();
return getControlsRowPresenter();
}
protected SparseArrayObjectAdapter createPrimaryActionsAdapter(
PresenterSelector presenterSelector) {
return super.createPrimaryActionsAdapter(presenterSelector);
}
/**
* Interface allowing the application to handle input events.
* @deprecated Use
* {@link PlaybackGlueHost#setOnKeyInterceptListener(View.OnKeyListener)}.
*/
@Deprecated
public interface InputEventHandler {
/**
* Called when an {@link InputEvent} is received.
*
* @return If the event should be consumed, return true. To allow the event to
* continue on to the next handler, return false.
*/
boolean handleInputEvent(InputEvent event);
}
static final class PlaybackGlueHostOld extends PlaybackGlueHost {
final PlaybackOverlayFragment mFragment;
PlaybackControlGlue mGlue;
OnActionClickedListener mActionClickedListener;
public PlaybackGlueHostOld(PlaybackOverlayFragment fragment) {
mFragment = fragment;
mFragment.setOnItemViewClickedListener(new OnItemViewClickedListener() {
@Override
public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
RowPresenter.ViewHolder rowViewHolder, Row row) {
if (item instanceof Action
&& rowViewHolder instanceof PlaybackRowPresenter.ViewHolder
&& mActionClickedListener != null) {
mActionClickedListener.onActionClicked((Action) item);
} else if (mGlue != null && mGlue.getOnItemViewClickedListener() != null) {
mGlue.getOnItemViewClickedListener().onItemClicked(itemViewHolder,
item, rowViewHolder, row);
}
}
});
}
@Override
public void setFadingEnabled(boolean enable) {
mFragment.setFadingEnabled(enable);
}
@Override
public void setOnKeyInterceptListener(final View.OnKeyListener onKeyListener) {
mFragment.setEventHandler( new InputEventHandler() {
@Override
public boolean handleInputEvent(InputEvent event) {
if (event instanceof KeyEvent) {
KeyEvent keyEvent = (KeyEvent) event;
return onKeyListener.onKey(null, keyEvent.getKeyCode(), keyEvent);
}
return false;
}
});
}
@Override
public void setOnActionClickedListener(final OnActionClickedListener listener) {
mActionClickedListener = listener;
}
@Override
public void setHostCallback(HostCallback callback) {
mFragment.setHostCallback(callback);
}
@Override
public void fadeOut() {
mFragment.fadeOut();
}
@Override
public void notifyPlaybackRowChanged() {
mGlue.onRowChanged(mGlue.getControlsRow());
}
}
}