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