186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn/*
286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * Copyright (C) 2015 The Android Open Source Project
386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn *
486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * in compliance with the License. You may obtain a copy of the License at
686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn *
786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * http://www.apache.org/licenses/LICENSE-2.0
886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn *
986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * Unless required by applicable law or agreed to in writing, software distributed under the License
1086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
1186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * or implied. See the License for the specific language governing permissions and limitations under
1286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * the License.
1386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn *
1486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn */
1586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
16ad31f63f5843898de645f6ee1ac244c872ded8ccRobert Hahnpackage android.support.v17.leanback.supportleanbackshowcase.app.media;
1786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
1886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.content.Context;
1986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.graphics.Color;
2086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.graphics.drawable.Drawable;
2186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.media.AudioManager;
2286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.media.MediaPlayer;
2386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.net.Uri;
2486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.os.Handler;
2586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.support.v17.leanback.app.PlaybackControlGlue;
2686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.support.v17.leanback.app.PlaybackOverlayFragment;
271dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiriimport android.support.v17.leanback.supportleanbackshowcase.R;
2886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.support.v17.leanback.widget.Action;
2986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.support.v17.leanback.widget.ArrayObjectAdapter;
3086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.support.v17.leanback.widget.ControlButtonPresenterSelector;
3186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.support.v17.leanback.widget.OnItemViewSelectedListener;
3286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.support.v17.leanback.widget.PlaybackControlsRow;
3386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
3486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.support.v17.leanback.widget.Presenter;
3586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.support.v17.leanback.widget.Row;
3686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.support.v17.leanback.widget.RowPresenter;
3786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.util.Log;
3886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.view.KeyEvent;
3986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.view.SurfaceHolder;
4086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport android.view.View;
4186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
4286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnimport java.io.IOException;
4386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
4486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn/**
4586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * This glue extends the {@link PlaybackControlGlue} with a {@link MediaPlayer} synchronization. It
4686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * supports 7 actions: <ul> <li>{@link android.support.v17.leanback.widget.PlaybackControlsRow.FastForwardAction}</li>
4786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * <li>{@link android.support.v17.leanback.widget.PlaybackControlsRow.RewindAction}</li> <li>{@link
4886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * android.support.v17.leanback.widget.PlaybackControlsRow.PlayPauseAction}</li> <li>{@link
4986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * android.support.v17.leanback.widget.PlaybackControlsRow.ShuffleAction}</li> <li>{@link
5086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * android.support.v17.leanback.widget.PlaybackControlsRow.RepeatAction}</li> <li>{@link
5186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsDownAction}</li> <li>{@link
5286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsUpAction}</li> </ul>
5386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn * <p/>
5486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn */
5586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahnpublic abstract class MediaPlayerGlue extends PlaybackControlGlue implements
5686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        OnItemViewSelectedListener {
5786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
5886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    public static final int FAST_FORWARD_REWIND_STEP = 10 * 1000; // in milliseconds
5986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    public static final int FAST_FORWARD_REWIND_REPEAT_DELAY = 200; // in milliseconds
6086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    private static final String TAG = "MediaPlayerGlue";
6186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    protected final PlaybackControlsRow.ThumbsDownAction mThumbsDownAction;
6286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    protected final PlaybackControlsRow.ThumbsUpAction mThumbsUpAction;
6386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    private final Context mContext;
6486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    private final MediaPlayer mPlayer = new MediaPlayer();
6586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    private final PlaybackControlsRow.RepeatAction mRepeatAction;
6686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    private final PlaybackControlsRow.ShuffleAction mShuffleAction;
6786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    private PlaybackControlsRow mControlsRow;
6886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    private Runnable mRunnable;
6986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    private Handler mHandler = new Handler();
7086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    private boolean mInitialized = false; // true when the MediaPlayer is prepared/initialized
7186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    private OnMediaFileFinishedPlayingListener mMediaFileFinishedPlayingListener;
7286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    private Action mSelectedAction; // the action which is currently selected by the user
7386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    private long mLastKeyDownEvent = 0L; // timestamp when the last DPAD_CENTER KEY_DOWN occurred
7486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    private MetaData mMetaData;
7586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    private Uri mMediaSourceUri = null;
7686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    private String mMediaSourcePath = null;
7786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
7886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    public MediaPlayerGlue(Context context, PlaybackOverlayFragment fragment) {
7986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        super(context, fragment, new int[]{1});
8086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mContext = context;
8186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
8286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        // Instantiate secondary actions
8386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mShuffleAction = new PlaybackControlsRow.ShuffleAction(mContext);
8486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mRepeatAction = new PlaybackControlsRow.RepeatAction(mContext);
8586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(mContext);
8686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(mContext);
8786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
8886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
8986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
9086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        // Register selected listener such that we know what action the user currently has focused.
9186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        fragment.setOnItemViewSelectedListener(this);
9286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
9386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
9486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    /**
9586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * Will reset the {@link MediaPlayer} and the glue such that a new file can be played. You are
9686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * not required to call this method before playing the first file. However you have to call it
9786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * before playing a second one.
9886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     */
991dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri    void reset() {
1001dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        mInitialized = false;
10186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mPlayer.reset();
10286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
10386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
10486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    public void setOnMediaFileFinishedPlayingListener(OnMediaFileFinishedPlayingListener listener) {
10586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mMediaFileFinishedPlayingListener = listener;
10686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
10786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
10886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    /**
10986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * Override this method in case you need to add different secondary actions.
11086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     *
11186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * @param secondaryActionsAdapter The adapter you need to add the {@link Action}s to.
11286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     */
11386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    protected void addSecondaryActions(ArrayObjectAdapter secondaryActionsAdapter) {
11486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        secondaryActionsAdapter.add(mShuffleAction);
11586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        secondaryActionsAdapter.add(mRepeatAction);
11686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        secondaryActionsAdapter.add(mThumbsDownAction);
11786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        secondaryActionsAdapter.add(mThumbsUpAction);
11886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
11986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
12086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    /**
12186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * @see MediaPlayer#setDisplay(SurfaceHolder)
12286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     */
12386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    public void setDisplay(SurfaceHolder surfaceHolder) {
12486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mPlayer.setDisplay(surfaceHolder);
12586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
12686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
12786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    /**
12886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * Use this method to setup the {@link PlaybackControlsRowPresenter}. It'll be called
12986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * <u>after</u> the {@link PlaybackControlsRowPresenter} has been created and the primary and
13086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * secondary actions have been added.
13186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     *
13286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * @param presenter The PlaybackControlsRowPresenter used to display the controls.
13386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     */
13486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    public void setupControlsRowPresenter(PlaybackControlsRowPresenter presenter) {
13586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        // TODO: hahnr@ move into resources
1365fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri        presenter.setProgressColor(getContext().getResources().getColor(
1375fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri                R.color.player_progress_color));
1385fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri        presenter.setBackgroundColor(getContext().getResources().getColor(
1395fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri                R.color.player_background_color));
14086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
14186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
14286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
14386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        PlaybackControlsRowPresenter presenter = super.createControlsRowAndPresenter();
14486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mControlsRow = getControlsRow();
14586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
14686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        // Add secondary actions and change the control row color.
14786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        ArrayObjectAdapter secondaryActions = new ArrayObjectAdapter(
14886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn                new ControlButtonPresenterSelector());
14986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mControlsRow.setSecondaryActionsAdapter(secondaryActions);
15086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        addSecondaryActions(secondaryActions);
15186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        setupControlsRowPresenter(presenter);
15286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        return presenter;
15386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
15486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
15586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override public void enableProgressUpdating(final boolean enabled) {
15686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        if (!enabled) {
15786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            if (mRunnable != null) mHandler.removeCallbacks(mRunnable);
15886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            return;
15986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        }
16086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mRunnable = new Runnable() {
16186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            @Override public void run() {
16286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn                updateProgress();
16386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn                Log.d(TAG, "enableProgressUpdating(boolean)");
16486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn                mHandler.postDelayed(this, getUpdatePeriod());
16586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            }
16686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        };
16786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mHandler.postDelayed(mRunnable, getUpdatePeriod());
16886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
16986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
17086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override public void onActionClicked(Action action) {
17186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        // If either 'Shuffle' or 'Repeat' has been clicked we need to make sure the acitons index
17286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        // is incremented and the UI updated such that we can display the new state.
17386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        super.onActionClicked(action);
17486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        if (action instanceof PlaybackControlsRow.ShuffleAction) {
17586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            mShuffleAction.nextIndex();
17686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        } else if (action instanceof PlaybackControlsRow.RepeatAction) {
17786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            mRepeatAction.nextIndex();
17886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        } else if (action instanceof PlaybackControlsRow.ThumbsUpAction) {
17986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            if (mThumbsUpAction.getIndex() == PlaybackControlsRow.ThumbsAction.SOLID) {
18086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn                mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
18186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            } else {
18286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn                mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.SOLID);
18386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn                mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
18486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            }
18586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        } else if (action instanceof PlaybackControlsRow.ThumbsDownAction) {
18686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            if (mThumbsDownAction.getIndex() == PlaybackControlsRow.ThumbsAction.SOLID) {
18786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn                mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
18886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            } else {
18986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn                mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.SOLID);
19086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn                mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
19186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            }
19286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        }
19386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        onMetadataChanged();
19486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
19586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
19686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override public boolean onKey(View v, int keyCode, KeyEvent event) {
19786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        // This method is overridden in order to make implement fast forwarding and rewinding when
19886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        // the user keeps the corresponding action pressed.
19986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        // We only consume DPAD_CENTER Action_DOWN events on the Fast-Forward and Rewind action and
20086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        // only if it has not been pressed in the last X milliseconds.
20186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        boolean consume = mSelectedAction instanceof PlaybackControlsRow.RewindAction;
20286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        consume = consume || mSelectedAction instanceof PlaybackControlsRow.FastForwardAction;
20386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        consume = consume && mInitialized;
20486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        consume = consume && event.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER;
20586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        consume = consume && event.getAction() == KeyEvent.ACTION_DOWN;
20686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        consume = consume && System
20786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn                .currentTimeMillis() - mLastKeyDownEvent > FAST_FORWARD_REWIND_REPEAT_DELAY;
20886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        if (consume) {
20986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            mLastKeyDownEvent = System.currentTimeMillis();
21086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            int newPosition = getCurrentPosition() + FAST_FORWARD_REWIND_STEP;
21186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            if (mSelectedAction instanceof PlaybackControlsRow.RewindAction) {
21286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn                newPosition = getCurrentPosition() - FAST_FORWARD_REWIND_STEP;
21386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            }
21486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            // Make sure the new calculated duration is in the range 0 >= X >= MediaDuration
21586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            if (newPosition < 0) newPosition = 0;
21686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            if (newPosition > getMediaDuration()) newPosition = getMediaDuration();
21786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            seekTo(newPosition);
21886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            return true;
21986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        }
22086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        return super.onKey(v, keyCode, event);
22186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
22286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
22386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override public boolean hasValidMedia() {
22486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        return mMetaData != null;
22586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
22686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
22786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override public boolean isMediaPlaying() {
22886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        return mPlayer.isPlaying();
22986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
23086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
23186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override public CharSequence getMediaTitle() {
23286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        return hasValidMedia() ? mMetaData.getTitle() : "N/a";
23386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
23486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
23586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override public CharSequence getMediaSubtitle() {
23686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        return hasValidMedia() ? mMetaData.getArtist() : "N/a";
23786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
23886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
23986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override public int getMediaDuration() {
24086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        return mInitialized ? mPlayer.getDuration() : 0;
24186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
24286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
24386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override public Drawable getMediaArt() {
24486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        return hasValidMedia() ? mMetaData.getCover() : null;
24586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
24686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
24786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override public long getSupportedActions() {
24886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        return PlaybackControlGlue.ACTION_PLAY_PAUSE | PlaybackControlGlue.ACTION_FAST_FORWARD | PlaybackControlGlue.ACTION_REWIND;
24986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
25086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
25186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override public int getCurrentSpeedId() {
25286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        // 0 = Pause, 1 = Normal Playback Speed
25386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        return mPlayer.isPlaying() ? 1 : 0;
25486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
25586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
25686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override public int getCurrentPosition() {
25786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        return mInitialized ? mPlayer.getCurrentPosition() : 0;
25886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
25986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
26086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override protected void startPlayback(int speed) throws IllegalStateException {
2611dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        mPlayer.start();
26286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
26386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
26486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override protected void pausePlayback() {
26586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        if (mPlayer.isPlaying()) {
26686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            mPlayer.pause();
26786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        }
26886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
26986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
27086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override protected void skipToNext() {
27186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        // Not supported.
27286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
27386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
27486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override protected void skipToPrevious() {
27586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        // Not supported.
27686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
27786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
27886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    /**
27986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * Called whenever the user presses fast-forward/rewind or when the user keeps the corresponding
28086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * action pressed.
28186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     *
28286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * @param newPosition The new position of the media track in milliseconds.
28386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     */
28486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    protected void seekTo(int newPosition) {
28586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mPlayer.seekTo(newPosition);
28686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
28786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
28886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    /**
2895fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri     * Sets the media source of the player witha given URI.
2905fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri     * @see MediaPlayer#setDataSource(String)
2915fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri     * @return Returns <code>true</code> if uri represents a new media; <code>false</code>
2925fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri     * otherwise.
29386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     */
2945fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri    public boolean setMediaSource(Uri uri) {
2951dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        if (mMediaSourceUri != null && mMediaSourceUri.equals(uri)) {
2965fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri            return false;
2971dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        }
29886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mMediaSourceUri = uri;
2995fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri        return true;
3005fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri    }
3015fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri
3025fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri    /**
3035fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri     * Sets the media source of the player with a String path URL.
3045fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri     * @see MediaPlayer#setDataSource(String)
3055fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri     * @return Returns <code>true</code> if path represents a new media; <code>false</code>
3065fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri     * otherwise.
3075fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri     */
3085fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri    public boolean setMediaSource(String path) {
3095fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri        if (mMediaSourcePath != null && mMediaSourcePath.equals(mMediaSourcePath)) {
3105fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri            return false;
3115fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri        }
3125fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri        mMediaSourcePath = path;
3135fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri        return true;
3145fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri    }
3155fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri
3165fc2bf47986ea74abe87e94186dd84d72205410bKeyvan Amiri    public void prepareMediaForPlaying() {
3171dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        reset();
3181dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        try {
3191dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri            if (mMediaSourceUri != null) mPlayer.setDataSource(getContext(), mMediaSourceUri);
3201dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri            else mPlayer.setDataSource(mMediaSourcePath);
3211dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        } catch (IOException e) {
3221dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri            throw new RuntimeException(e);
3231dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        }
3241dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
3251dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
3261dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri            @Override public void onPrepared(MediaPlayer mp) {
3271dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri                mInitialized = true;
3281dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri                mPlayer.start();
3291dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri                onMetadataChanged();
3301dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri                onStateChanged();
3311dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri                updateProgress();
3321dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri            }
3331dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        });
3341dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
3351dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri            @Override public void onCompletion(MediaPlayer mp) {
3361dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri                if (mInitialized && mMediaFileFinishedPlayingListener != null)
3371dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri                    mMediaFileFinishedPlayingListener.onMediaFileFinishedPlaying(mMetaData);
3381dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri            }
3391dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        });
3401dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        mPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
3411dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri            @Override public void onBufferingUpdate(MediaPlayer mp, int percent) {
3421dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri                mControlsRow.setBufferedProgress((int) (mp.getDuration() * (percent / 100f)));
3431dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri            }
3441dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        });
3451dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        mPlayer.prepareAsync();
3461dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri        onStateChanged();
34786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
34886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
34986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    /**
35086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * Call to <code>startPlayback(1)</code>.
35186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     *
35286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * @throws IllegalStateException See {@link MediaPlayer} for further information about it's
35386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * different states when setting a data source and preparing it to be played.
35486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     */
35586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    public void startPlayback() throws IllegalStateException {
35686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        startPlayback(1);
35786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
35886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
35986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    /**
36086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * @return Returns <code>true</code> iff 'Shuffle' is <code>ON</code>.
36186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     */
36286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    public boolean useShuffle() {
36386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        return mShuffleAction.getIndex() == PlaybackControlsRow.ShuffleAction.ON;
36486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
36586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
36686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    /**
36786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * @return Returns <code>true</code> iff 'Repeat-One' is <code>ON</code>.
36886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     */
36986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    public boolean repeatOne() {
37086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        return mRepeatAction.getIndex() == PlaybackControlsRow.RepeatAction.ONE;
37186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
37286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
37386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    /**
37486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * @return Returns <code>true</code> iff 'Repeat-All' is <code>ON</code>.
37586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     */
37686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    public boolean repeatAll() {
37786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        return mRepeatAction.getIndex() == PlaybackControlsRow.RepeatAction.ALL;
37886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
37986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
38086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    public void setMetaData(MetaData metaData) {
38186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        mMetaData = metaData;
38286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        onMetadataChanged();
38386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
38486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
38586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    /**
38686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * This is a listener implementation for the {@link OnItemViewSelectedListener} of the {@link
38786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * PlaybackOverlayFragment}. This implementation is required in order to detect KEY_DOWN events
38886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * on the {@link android.support.v17.leanback.widget.PlaybackControlsRow.FastForwardAction} and
38986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * {@link android.support.v17.leanback.widget.PlaybackControlsRow.RewindAction}. Thus you should
39086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * <u>NOT</u> set another {@link OnItemViewSelectedListener} on your {@link
39186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * PlaybackOverlayFragment}. Instead, override this method and call its super (this)
39286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * implementation.
39386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     *
39486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * @see OnItemViewSelectedListener#onItemSelected(Presenter.ViewHolder, Object,
39586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * RowPresenter.ViewHolder, Row)
39686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     */
39786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    @Override public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
39886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn                                         RowPresenter.ViewHolder rowViewHolder, Row row) {
39986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        if (item instanceof Action) {
40086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            mSelectedAction = (Action) item;
40186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        } else {
40286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            mSelectedAction = null;
40386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        }
40486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
40586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
40686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    /**
40786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * A listener which will be called whenever a track is finished playing.
40886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     */
40986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    public interface OnMediaFileFinishedPlayingListener {
41086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
41186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        /**
41286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn         * Called when a track is finished playing.
41386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn         *
41486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn         * @param metaData The track's {@link MetaData} which just finished playing.
41586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn         */
41686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        void onMediaFileFinishedPlaying(MetaData metaData);
41786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
41886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
41986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
42086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    /**
42186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * Holds the meta data such as track title, artist and cover art. It'll be used by the {@link
42286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     * MediaPlayerGlue}.
42386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn     */
42486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    public static class MetaData {
42586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
42686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        private String mTitle;
42786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        private String mArtist;
42886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        private Drawable mCover;
42986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
43086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        public String getTitle() {
43186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            return mTitle;
43286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        }
43386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
43486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        public void setTitle(String title) {
43586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            this.mTitle = title;
43686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        }
43786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
43886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        public String getArtist() {
43986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            return mArtist;
44086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        }
44186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
44286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        public void setArtist(String artist) {
44386163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            this.mArtist = artist;
44486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        }
44586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
44686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        public Drawable getCover() {
44786163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            return mCover;
44886163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        }
44986163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
45086163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        public void setCover(Drawable cover) {
45186163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn            this.mCover = cover;
45286163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn        }
4531dd934eb3d2aa4e685585fa0f26c738feee0db4cKeyvan Amiri
45486163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn    }
45586163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn
45686163d539e1aeb9ae7612def7aaf7dbfc5b88f28Robert Hahn}
457