14702556bfd15c9819a7b2af759aee0f719cd631fsusnata/*
295ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu * Copyright (C) 2016 The Android Open Source Project
34702556bfd15c9819a7b2af759aee0f719cd631fsusnata *
495ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu * Licensed under the Apache License, Version 2.0 (the "License");
595ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu * you may not use this file except in compliance with the License.
695ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu * You may obtain a copy of the License at
74702556bfd15c9819a7b2af759aee0f719cd631fsusnata *
895ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu *      http://www.apache.org/licenses/LICENSE-2.0
94702556bfd15c9819a7b2af759aee0f719cd631fsusnata *
1095ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu * Unless required by applicable law or agreed to in writing, software
1195ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu * distributed under the License is distributed on an "AS IS" BASIS,
1295ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1395ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu * See the License for the specific language governing permissions and
1495ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu * limitations under the License.
154702556bfd15c9819a7b2af759aee0f719cd631fsusnata */
164702556bfd15c9819a7b2af759aee0f719cd631fsusnata
17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.leanback.media;
184702556bfd15c9819a7b2af759aee0f719cd631fsusnata
194702556bfd15c9819a7b2af759aee0f719cd631fsusnataimport android.content.Context;
204702556bfd15c9819a7b2af759aee0f719cd631fsusnataimport android.graphics.drawable.Drawable;
214702556bfd15c9819a7b2af759aee0f719cd631fsusnataimport android.media.AudioManager;
224702556bfd15c9819a7b2af759aee0f719cd631fsusnataimport android.media.MediaPlayer;
234702556bfd15c9819a7b2af759aee0f719cd631fsusnataimport android.net.Uri;
244702556bfd15c9819a7b2af759aee0f719cd631fsusnataimport android.os.Handler;
258619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport android.view.KeyEvent;
268619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport android.view.SurfaceHolder;
278619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport android.view.View;
288619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikas
29ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.RestrictTo;
30ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.leanback.widget.Action;
31ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.leanback.widget.ArrayObjectAdapter;
32ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.leanback.widget.OnItemViewSelectedListener;
33ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.leanback.widget.PlaybackControlsRow;
34ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.leanback.widget.Presenter;
35ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.leanback.widget.Row;
36ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.leanback.widget.RowPresenter;
374702556bfd15c9819a7b2af759aee0f719cd631fsusnata
384702556bfd15c9819a7b2af759aee0f719cd631fsusnataimport java.io.IOException;
393bcad88cbf4488e747d84893c35f2351b8f84afeDake Guimport java.util.List;
404702556bfd15c9819a7b2af759aee0f719cd631fsusnata
414702556bfd15c9819a7b2af759aee0f719cd631fsusnata/**
42ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * This glue extends the {@link androidx.leanback.media.PlaybackControlGlue} with a
4395ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu * {@link MediaPlayer} synchronization. It supports 7 actions:
444702556bfd15c9819a7b2af759aee0f719cd631fsusnata *
454702556bfd15c9819a7b2af759aee0f719cd631fsusnata * <ul>
46ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * <li>{@link androidx.leanback.widget.PlaybackControlsRow.FastForwardAction}</li>
47ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * <li>{@link androidx.leanback.widget.PlaybackControlsRow.RewindAction}</li>
48ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * <li>{@link  androidx.leanback.widget.PlaybackControlsRow.PlayPauseAction}</li>
49ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * <li>{@link androidx.leanback.widget.PlaybackControlsRow.RepeatAction}</li>
50ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * <li>{@link androidx.leanback.widget.PlaybackControlsRow.ThumbsDownAction}</li>
51ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * <li>{@link androidx.leanback.widget.PlaybackControlsRow.ThumbsUpAction}</li>
524702556bfd15c9819a7b2af759aee0f719cd631fsusnata * </ul>
534702556bfd15c9819a7b2af759aee0f719cd631fsusnata *
544702556bfd15c9819a7b2af759aee0f719cd631fsusnata * @hide
559f7da98dbcd12a0bbd48a563ff82fdcba7de3deaDake Gu * @deprecated Use {@link MediaPlayerAdapter} with {@link PlaybackTransportControlGlue} or
569f7da98dbcd12a0bbd48a563ff82fdcba7de3deaDake Gu *             {@link PlaybackBannerControlGlue}.
574702556bfd15c9819a7b2af759aee0f719cd631fsusnata */
589f7da98dbcd12a0bbd48a563ff82fdcba7de3deaDake Gu@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
599f7da98dbcd12a0bbd48a563ff82fdcba7de3deaDake Gu@Deprecated
604702556bfd15c9819a7b2af759aee0f719cd631fsusnatapublic class MediaPlayerGlue extends PlaybackControlGlue implements
614702556bfd15c9819a7b2af759aee0f719cd631fsusnata        OnItemViewSelectedListener {
624702556bfd15c9819a7b2af759aee0f719cd631fsusnata
634702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public static final int NO_REPEAT = 0;
644702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public static final int REPEAT_ONE = 1;
654702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public static final int REPEAT_ALL = 2;
664702556bfd15c9819a7b2af759aee0f719cd631fsusnata
674702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public static final int FAST_FORWARD_REWIND_STEP = 10 * 1000; // in milliseconds
684702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public static final int FAST_FORWARD_REWIND_REPEAT_DELAY = 200; // in milliseconds
694702556bfd15c9819a7b2af759aee0f719cd631fsusnata    private static final String TAG = "MediaPlayerGlue";
704702556bfd15c9819a7b2af759aee0f719cd631fsusnata    protected final PlaybackControlsRow.ThumbsDownAction mThumbsDownAction;
714702556bfd15c9819a7b2af759aee0f719cd631fsusnata    protected final PlaybackControlsRow.ThumbsUpAction mThumbsUpAction;
724702556bfd15c9819a7b2af759aee0f719cd631fsusnata    MediaPlayer mPlayer = new MediaPlayer();
734702556bfd15c9819a7b2af759aee0f719cd631fsusnata    private final PlaybackControlsRow.RepeatAction mRepeatAction;
744702556bfd15c9819a7b2af759aee0f719cd631fsusnata    private Runnable mRunnable;
754702556bfd15c9819a7b2af759aee0f719cd631fsusnata    private Handler mHandler = new Handler();
764702556bfd15c9819a7b2af759aee0f719cd631fsusnata    private boolean mInitialized = false; // true when the MediaPlayer is prepared/initialized
774702556bfd15c9819a7b2af759aee0f719cd631fsusnata    private Action mSelectedAction; // the action which is currently selected by the user
784702556bfd15c9819a7b2af759aee0f719cd631fsusnata    private long mLastKeyDownEvent = 0L; // timestamp when the last DPAD_CENTER KEY_DOWN occurred
794702556bfd15c9819a7b2af759aee0f719cd631fsusnata    private Uri mMediaSourceUri = null;
804702556bfd15c9819a7b2af759aee0f719cd631fsusnata    private String mMediaSourcePath = null;
814702556bfd15c9819a7b2af759aee0f719cd631fsusnata    private MediaPlayer.OnCompletionListener mOnCompletionListener;
824702556bfd15c9819a7b2af759aee0f719cd631fsusnata    private String mArtist;
834702556bfd15c9819a7b2af759aee0f719cd631fsusnata    private String mTitle;
844702556bfd15c9819a7b2af759aee0f719cd631fsusnata    private Drawable mCover;
854702556bfd15c9819a7b2af759aee0f719cd631fsusnata
864702556bfd15c9819a7b2af759aee0f719cd631fsusnata    /**
874702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * Sets the drawable representing cover image.
884702556bfd15c9819a7b2af759aee0f719cd631fsusnata     */
894702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public void setCover(Drawable cover) {
904702556bfd15c9819a7b2af759aee0f719cd631fsusnata        this.mCover = cover;
914702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
924702556bfd15c9819a7b2af759aee0f719cd631fsusnata
934702556bfd15c9819a7b2af759aee0f719cd631fsusnata    /**
944702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * Sets the artist name.
954702556bfd15c9819a7b2af759aee0f719cd631fsusnata     */
964702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public void setArtist(String artist) {
974702556bfd15c9819a7b2af759aee0f719cd631fsusnata        this.mArtist = artist;
984702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
994702556bfd15c9819a7b2af759aee0f719cd631fsusnata
1004702556bfd15c9819a7b2af759aee0f719cd631fsusnata    /**
1014702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * Sets the media title.
1024702556bfd15c9819a7b2af759aee0f719cd631fsusnata     */
1034702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public void setTitle(String title) {
1044702556bfd15c9819a7b2af759aee0f719cd631fsusnata        this.mTitle = title;
1054702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
1064702556bfd15c9819a7b2af759aee0f719cd631fsusnata
1074702556bfd15c9819a7b2af759aee0f719cd631fsusnata    /**
1084702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * Sets the url for the video.
1094702556bfd15c9819a7b2af759aee0f719cd631fsusnata     */
1104702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public void setVideoUrl(String videoUrl) {
1114702556bfd15c9819a7b2af759aee0f719cd631fsusnata        setMediaSource(videoUrl);
1124702556bfd15c9819a7b2af759aee0f719cd631fsusnata        onMetadataChanged();
1134702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
1144702556bfd15c9819a7b2af759aee0f719cd631fsusnata
1154702556bfd15c9819a7b2af759aee0f719cd631fsusnata    /**
1164702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * Constructor.
1174702556bfd15c9819a7b2af759aee0f719cd631fsusnata     */
11895ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu    public MediaPlayerGlue(Context context) {
11995ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu        this(context, new int[]{1}, new int[]{1});
1204702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
1214702556bfd15c9819a7b2af759aee0f719cd631fsusnata
1224702556bfd15c9819a7b2af759aee0f719cd631fsusnata    /**
1234702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * Constructor.
1244702556bfd15c9819a7b2af759aee0f719cd631fsusnata     */
1254702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public MediaPlayerGlue(
12695ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu            Context context, int[] fastForwardSpeeds, int[] rewindSpeeds) {
12795ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu        super(context, fastForwardSpeeds, rewindSpeeds);
1284702556bfd15c9819a7b2af759aee0f719cd631fsusnata
1294702556bfd15c9819a7b2af759aee0f719cd631fsusnata        // Instantiate secondary actions
13095ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu        mRepeatAction = new PlaybackControlsRow.RepeatAction(getContext());
13195ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu        mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(getContext());
13295ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu        mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(getContext());
133946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu        mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.INDEX_OUTLINE);
134946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu        mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.INDEX_OUTLINE);
1354702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
1364702556bfd15c9819a7b2af759aee0f719cd631fsusnata
1374702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
13895ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu    protected void onAttachedToHost(PlaybackGlueHost host) {
13995ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu        super.onAttachedToHost(host);
14095ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu        if (host instanceof SurfaceHolderGlueHost) {
14195ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu            ((SurfaceHolderGlueHost) host).setSurfaceHolderCallback(
14295ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu                    new VideoPlayerSurfaceHolderCallback());
1434702556bfd15c9819a7b2af759aee0f719cd631fsusnata        }
1444702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
1454702556bfd15c9819a7b2af759aee0f719cd631fsusnata
1464702556bfd15c9819a7b2af759aee0f719cd631fsusnata    /**
1474702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * Will reset the {@link MediaPlayer} and the glue such that a new file can be played. You are
1484702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * not required to call this method before playing the first file. However you have to call it
1494702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * before playing a second one.
1504702556bfd15c9819a7b2af759aee0f719cd631fsusnata     */
151aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata    public void reset() {
1523bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        changeToUnitialized();
1534702556bfd15c9819a7b2af759aee0f719cd631fsusnata        mPlayer.reset();
1544702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
1554702556bfd15c9819a7b2af759aee0f719cd631fsusnata
1563bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    void changeToUnitialized() {
1573bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        if (mInitialized) {
1583bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            mInitialized = false;
1593bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            List<PlayerCallback> callbacks = getPlayerCallbacks();
1603bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            if (callbacks != null) {
1613bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                for (PlayerCallback callback: callbacks) {
1623bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    callback.onPreparedStateChanged(MediaPlayerGlue.this);
1633bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                }
1643bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            }
1653bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        }
1663bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
1673bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
16895ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu    /**
16995ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu     * Release internal MediaPlayer. Should not use the object after call release().
17095ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu     */
171aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata    public void release() {
1723bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        changeToUnitialized();
173aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata        mPlayer.release();
174aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata    }
175aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata
176aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata    @Override
17795ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu    protected void onDetachedFromHost() {
1783961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu        if (getHost() instanceof SurfaceHolderGlueHost) {
1793961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu            ((SurfaceHolderGlueHost) getHost()).setSurfaceHolderCallback(null);
1803961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu        }
181aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata        reset();
182aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata        release();
1833961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu        super.onDetachedFromHost();
184aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata    }
185aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata
18695ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu    @Override
18795ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu    protected void onCreateSecondaryActions(ArrayObjectAdapter secondaryActionsAdapter) {
1884702556bfd15c9819a7b2af759aee0f719cd631fsusnata        secondaryActionsAdapter.add(mRepeatAction);
1894702556bfd15c9819a7b2af759aee0f719cd631fsusnata        secondaryActionsAdapter.add(mThumbsDownAction);
1904702556bfd15c9819a7b2af759aee0f719cd631fsusnata        secondaryActionsAdapter.add(mThumbsUpAction);
1914702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
1924702556bfd15c9819a7b2af759aee0f719cd631fsusnata
1934702556bfd15c9819a7b2af759aee0f719cd631fsusnata    /**
1944702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * @see MediaPlayer#setDisplay(SurfaceHolder)
1954702556bfd15c9819a7b2af759aee0f719cd631fsusnata     */
1964702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public void setDisplay(SurfaceHolder surfaceHolder) {
1974702556bfd15c9819a7b2af759aee0f719cd631fsusnata        mPlayer.setDisplay(surfaceHolder);
1984702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
1994702556bfd15c9819a7b2af759aee0f719cd631fsusnata
2004702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
2014702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public void enableProgressUpdating(final boolean enabled) {
2023961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu        if (mRunnable != null) mHandler.removeCallbacks(mRunnable);
2034702556bfd15c9819a7b2af759aee0f719cd631fsusnata        if (!enabled) {
2044702556bfd15c9819a7b2af759aee0f719cd631fsusnata            return;
2054702556bfd15c9819a7b2af759aee0f719cd631fsusnata        }
2063961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu        if (mRunnable == null) {
2073961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu            mRunnable = new Runnable() {
2083961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu                @Override
2093961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu                public void run() {
2103961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu                    updateProgress();
2113961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu                    mHandler.postDelayed(this, getUpdatePeriod());
2123961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu                }
2133961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu            };
2143961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu        }
2154702556bfd15c9819a7b2af759aee0f719cd631fsusnata        mHandler.postDelayed(mRunnable, getUpdatePeriod());
2164702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
2174702556bfd15c9819a7b2af759aee0f719cd631fsusnata
2184702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
2194702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public void onActionClicked(Action action) {
2204702556bfd15c9819a7b2af759aee0f719cd631fsusnata        // If either 'Shuffle' or 'Repeat' has been clicked we need to make sure the actions index
2214702556bfd15c9819a7b2af759aee0f719cd631fsusnata        // is incremented and the UI updated such that we can display the new state.
2224702556bfd15c9819a7b2af759aee0f719cd631fsusnata        super.onActionClicked(action);
2234702556bfd15c9819a7b2af759aee0f719cd631fsusnata        if (action instanceof PlaybackControlsRow.RepeatAction) {
224946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu            ((PlaybackControlsRow.RepeatAction) action).nextIndex();
225946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu        } else if (action == mThumbsUpAction) {
226946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu            if (mThumbsUpAction.getIndex() == PlaybackControlsRow.ThumbsAction.INDEX_SOLID) {
227946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu                mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.INDEX_OUTLINE);
2284702556bfd15c9819a7b2af759aee0f719cd631fsusnata            } else {
229946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu                mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.INDEX_SOLID);
230946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu                mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.INDEX_OUTLINE);
2314702556bfd15c9819a7b2af759aee0f719cd631fsusnata            }
232946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu        } else if (action == mThumbsDownAction) {
233946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu            if (mThumbsDownAction.getIndex() == PlaybackControlsRow.ThumbsAction.INDEX_SOLID) {
234946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu                mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.INDEX_OUTLINE);
2354702556bfd15c9819a7b2af759aee0f719cd631fsusnata            } else {
236946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu                mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.INDEX_SOLID);
237946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu                mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.INDEX_OUTLINE);
2384702556bfd15c9819a7b2af759aee0f719cd631fsusnata            }
2394702556bfd15c9819a7b2af759aee0f719cd631fsusnata        }
2404702556bfd15c9819a7b2af759aee0f719cd631fsusnata        onMetadataChanged();
2414702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
2424702556bfd15c9819a7b2af759aee0f719cd631fsusnata
2434702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
2444702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public boolean onKey(View v, int keyCode, KeyEvent event) {
2454702556bfd15c9819a7b2af759aee0f719cd631fsusnata        // This method is overridden in order to make implement fast forwarding and rewinding when
2464702556bfd15c9819a7b2af759aee0f719cd631fsusnata        // the user keeps the corresponding action pressed.
2474702556bfd15c9819a7b2af759aee0f719cd631fsusnata        // We only consume DPAD_CENTER Action_DOWN events on the Fast-Forward and Rewind action and
2484702556bfd15c9819a7b2af759aee0f719cd631fsusnata        // only if it has not been pressed in the last X milliseconds.
2494702556bfd15c9819a7b2af759aee0f719cd631fsusnata        boolean consume = mSelectedAction instanceof PlaybackControlsRow.RewindAction;
2504702556bfd15c9819a7b2af759aee0f719cd631fsusnata        consume = consume || mSelectedAction instanceof PlaybackControlsRow.FastForwardAction;
2514702556bfd15c9819a7b2af759aee0f719cd631fsusnata        consume = consume && mInitialized;
2524702556bfd15c9819a7b2af759aee0f719cd631fsusnata        consume = consume && event.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER;
2534702556bfd15c9819a7b2af759aee0f719cd631fsusnata        consume = consume && event.getAction() == KeyEvent.ACTION_DOWN;
2544702556bfd15c9819a7b2af759aee0f719cd631fsusnata        consume = consume && System
2554702556bfd15c9819a7b2af759aee0f719cd631fsusnata                .currentTimeMillis() - mLastKeyDownEvent > FAST_FORWARD_REWIND_REPEAT_DELAY;
2564702556bfd15c9819a7b2af759aee0f719cd631fsusnata
2574702556bfd15c9819a7b2af759aee0f719cd631fsusnata        if (consume) {
2584702556bfd15c9819a7b2af759aee0f719cd631fsusnata            mLastKeyDownEvent = System.currentTimeMillis();
2594702556bfd15c9819a7b2af759aee0f719cd631fsusnata            int newPosition = getCurrentPosition() + FAST_FORWARD_REWIND_STEP;
2604702556bfd15c9819a7b2af759aee0f719cd631fsusnata            if (mSelectedAction instanceof PlaybackControlsRow.RewindAction) {
2614702556bfd15c9819a7b2af759aee0f719cd631fsusnata                newPosition = getCurrentPosition() - FAST_FORWARD_REWIND_STEP;
2624702556bfd15c9819a7b2af759aee0f719cd631fsusnata            }
2634702556bfd15c9819a7b2af759aee0f719cd631fsusnata            // Make sure the new calculated duration is in the range 0 >= X >= MediaDuration
2644702556bfd15c9819a7b2af759aee0f719cd631fsusnata            if (newPosition < 0) newPosition = 0;
2654702556bfd15c9819a7b2af759aee0f719cd631fsusnata            if (newPosition > getMediaDuration()) newPosition = getMediaDuration();
2664702556bfd15c9819a7b2af759aee0f719cd631fsusnata            seekTo(newPosition);
2674702556bfd15c9819a7b2af759aee0f719cd631fsusnata            return true;
2684702556bfd15c9819a7b2af759aee0f719cd631fsusnata        }
2694702556bfd15c9819a7b2af759aee0f719cd631fsusnata
2704702556bfd15c9819a7b2af759aee0f719cd631fsusnata        return super.onKey(v, keyCode, event);
2714702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
2724702556bfd15c9819a7b2af759aee0f719cd631fsusnata
2734702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
2744702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public boolean hasValidMedia() {
275aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata        return mTitle != null && (mMediaSourcePath != null || mMediaSourceUri != null);
2764702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
2774702556bfd15c9819a7b2af759aee0f719cd631fsusnata
2784702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
2794702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public boolean isMediaPlaying() {
280f37579e64940bfdd642cc315f6347d60b5addd69Dake Gu        return mInitialized && mPlayer.isPlaying();
2814702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
2824702556bfd15c9819a7b2af759aee0f719cd631fsusnata
2834702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
2843bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    public boolean isPlaying() {
2853bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        return isMediaPlaying();
2863bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
2873bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
2883bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    @Override
2894702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public CharSequence getMediaTitle() {
2904702556bfd15c9819a7b2af759aee0f719cd631fsusnata        return mTitle != null ? mTitle : "N/a";
2914702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
2924702556bfd15c9819a7b2af759aee0f719cd631fsusnata
2934702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
2944702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public CharSequence getMediaSubtitle() {
2954702556bfd15c9819a7b2af759aee0f719cd631fsusnata        return mArtist != null ? mArtist : "N/a";
2964702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
2974702556bfd15c9819a7b2af759aee0f719cd631fsusnata
2984702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
2994702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public int getMediaDuration() {
3004702556bfd15c9819a7b2af759aee0f719cd631fsusnata        return mInitialized ? mPlayer.getDuration() : 0;
3014702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
3024702556bfd15c9819a7b2af759aee0f719cd631fsusnata
3034702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
3044702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public Drawable getMediaArt() {
3054702556bfd15c9819a7b2af759aee0f719cd631fsusnata        return mCover;
3064702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
3074702556bfd15c9819a7b2af759aee0f719cd631fsusnata
3084702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
3094702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public long getSupportedActions() {
3104702556bfd15c9819a7b2af759aee0f719cd631fsusnata        return PlaybackControlGlue.ACTION_PLAY_PAUSE
3114702556bfd15c9819a7b2af759aee0f719cd631fsusnata                | PlaybackControlGlue.ACTION_FAST_FORWARD
3124702556bfd15c9819a7b2af759aee0f719cd631fsusnata                | PlaybackControlGlue.ACTION_REWIND;
3134702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
3144702556bfd15c9819a7b2af759aee0f719cd631fsusnata
3154702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
3164702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public int getCurrentSpeedId() {
3174702556bfd15c9819a7b2af759aee0f719cd631fsusnata        // 0 = Pause, 1 = Normal Playback Speed
318f37579e64940bfdd642cc315f6347d60b5addd69Dake Gu        return isMediaPlaying() ? 1 : 0;
3194702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
3204702556bfd15c9819a7b2af759aee0f719cd631fsusnata
3214702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
3224702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public int getCurrentPosition() {
3234702556bfd15c9819a7b2af759aee0f719cd631fsusnata        return mInitialized ? mPlayer.getCurrentPosition() : 0;
3244702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
3254702556bfd15c9819a7b2af759aee0f719cd631fsusnata
3264702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
32795ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu    public void play(int speed) {
3283961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu        if (!mInitialized || mPlayer.isPlaying()) {
3293961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu            return;
3303961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu        }
3314702556bfd15c9819a7b2af759aee0f719cd631fsusnata        mPlayer.start();
3324702556bfd15c9819a7b2af759aee0f719cd631fsusnata        onMetadataChanged();
3334702556bfd15c9819a7b2af759aee0f719cd631fsusnata        onStateChanged();
3344702556bfd15c9819a7b2af759aee0f719cd631fsusnata        updateProgress();
3354702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
3364702556bfd15c9819a7b2af759aee0f719cd631fsusnata
3374702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
3384702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public void pause() {
339f37579e64940bfdd642cc315f6347d60b5addd69Dake Gu        if (isMediaPlaying()) {
3404702556bfd15c9819a7b2af759aee0f719cd631fsusnata            mPlayer.pause();
3413961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu            onStateChanged();
3424702556bfd15c9819a7b2af759aee0f719cd631fsusnata        }
3434702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
3444702556bfd15c9819a7b2af759aee0f719cd631fsusnata
3454702556bfd15c9819a7b2af759aee0f719cd631fsusnata    /**
3464702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * Sets the playback mode. It currently support no repeat, repeat once and infinite
3474702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * loop mode.
3484702556bfd15c9819a7b2af759aee0f719cd631fsusnata     */
3494702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public void setMode(int mode) {
3504702556bfd15c9819a7b2af759aee0f719cd631fsusnata        switch(mode) {
3514702556bfd15c9819a7b2af759aee0f719cd631fsusnata            case NO_REPEAT:
3524702556bfd15c9819a7b2af759aee0f719cd631fsusnata                mOnCompletionListener = null;
3534702556bfd15c9819a7b2af759aee0f719cd631fsusnata                break;
3544702556bfd15c9819a7b2af759aee0f719cd631fsusnata            case REPEAT_ONE:
3554702556bfd15c9819a7b2af759aee0f719cd631fsusnata                mOnCompletionListener = new MediaPlayer.OnCompletionListener() {
3564702556bfd15c9819a7b2af759aee0f719cd631fsusnata                    public boolean mFirstRepeat;
3574702556bfd15c9819a7b2af759aee0f719cd631fsusnata
3584702556bfd15c9819a7b2af759aee0f719cd631fsusnata                    @Override
3594702556bfd15c9819a7b2af759aee0f719cd631fsusnata                    public void onCompletion(MediaPlayer mediaPlayer) {
3604702556bfd15c9819a7b2af759aee0f719cd631fsusnata                        if (!mFirstRepeat) {
3614702556bfd15c9819a7b2af759aee0f719cd631fsusnata                            mFirstRepeat = true;
3624702556bfd15c9819a7b2af759aee0f719cd631fsusnata                            mediaPlayer.setOnCompletionListener(null);
3634702556bfd15c9819a7b2af759aee0f719cd631fsusnata                        }
3644702556bfd15c9819a7b2af759aee0f719cd631fsusnata                        play();
3654702556bfd15c9819a7b2af759aee0f719cd631fsusnata                    }
3664702556bfd15c9819a7b2af759aee0f719cd631fsusnata                };
3674702556bfd15c9819a7b2af759aee0f719cd631fsusnata                break;
3684702556bfd15c9819a7b2af759aee0f719cd631fsusnata            case REPEAT_ALL:
3694702556bfd15c9819a7b2af759aee0f719cd631fsusnata                mOnCompletionListener = new MediaPlayer.OnCompletionListener() {
3704702556bfd15c9819a7b2af759aee0f719cd631fsusnata                    @Override
3714702556bfd15c9819a7b2af759aee0f719cd631fsusnata                    public void onCompletion(MediaPlayer mediaPlayer) {
3724702556bfd15c9819a7b2af759aee0f719cd631fsusnata                        play();
3734702556bfd15c9819a7b2af759aee0f719cd631fsusnata                    }
3744702556bfd15c9819a7b2af759aee0f719cd631fsusnata                };
3754702556bfd15c9819a7b2af759aee0f719cd631fsusnata                break;
3764702556bfd15c9819a7b2af759aee0f719cd631fsusnata        }
3774702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
3784702556bfd15c9819a7b2af759aee0f719cd631fsusnata
3794702556bfd15c9819a7b2af759aee0f719cd631fsusnata    /**
3804702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * Called whenever the user presses fast-forward/rewind or when the user keeps the
3814702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * corresponding action pressed.
3824702556bfd15c9819a7b2af759aee0f719cd631fsusnata     *
3834702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * @param newPosition The new position of the media track in milliseconds.
3844702556bfd15c9819a7b2af759aee0f719cd631fsusnata     */
3854702556bfd15c9819a7b2af759aee0f719cd631fsusnata    protected void seekTo(int newPosition) {
386f37579e64940bfdd642cc315f6347d60b5addd69Dake Gu        if (!mInitialized) {
387f37579e64940bfdd642cc315f6347d60b5addd69Dake Gu            return;
388f37579e64940bfdd642cc315f6347d60b5addd69Dake Gu        }
3894702556bfd15c9819a7b2af759aee0f719cd631fsusnata        mPlayer.seekTo(newPosition);
3904702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
3914702556bfd15c9819a7b2af759aee0f719cd631fsusnata
3924702556bfd15c9819a7b2af759aee0f719cd631fsusnata    /**
3934702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * Sets the media source of the player witha given URI.
3944702556bfd15c9819a7b2af759aee0f719cd631fsusnata     *
3954702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * @return Returns <code>true</code> if uri represents a new media; <code>false</code>
3964702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * otherwise.
3974702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * @see MediaPlayer#setDataSource(String)
3984702556bfd15c9819a7b2af759aee0f719cd631fsusnata     */
3994702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public boolean setMediaSource(Uri uri) {
400694edde99dc3782374977dab6d9aa34a16c13337Dake Gu        if (mMediaSourceUri != null ? mMediaSourceUri.equals(uri) : uri == null) {
4014702556bfd15c9819a7b2af759aee0f719cd631fsusnata            return false;
4024702556bfd15c9819a7b2af759aee0f719cd631fsusnata        }
403694edde99dc3782374977dab6d9aa34a16c13337Dake Gu        mMediaSourceUri = uri;
404694edde99dc3782374977dab6d9aa34a16c13337Dake Gu        mMediaSourcePath = null;
405694edde99dc3782374977dab6d9aa34a16c13337Dake Gu        prepareMediaForPlaying();
4064702556bfd15c9819a7b2af759aee0f719cd631fsusnata        return true;
4074702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
4084702556bfd15c9819a7b2af759aee0f719cd631fsusnata
4094702556bfd15c9819a7b2af759aee0f719cd631fsusnata    /**
4104702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * Sets the media source of the player with a String path URL.
4114702556bfd15c9819a7b2af759aee0f719cd631fsusnata     *
4124702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * @return Returns <code>true</code> if path represents a new media; <code>false</code>
4134702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * otherwise.
4144702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * @see MediaPlayer#setDataSource(String)
4154702556bfd15c9819a7b2af759aee0f719cd631fsusnata     */
4164702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public boolean setMediaSource(String path) {
417694edde99dc3782374977dab6d9aa34a16c13337Dake Gu        if (mMediaSourcePath != null ? mMediaSourcePath.equals(path) : path == null) {
4184702556bfd15c9819a7b2af759aee0f719cd631fsusnata            return false;
4194702556bfd15c9819a7b2af759aee0f719cd631fsusnata        }
420694edde99dc3782374977dab6d9aa34a16c13337Dake Gu        mMediaSourceUri = null;
421694edde99dc3782374977dab6d9aa34a16c13337Dake Gu        mMediaSourcePath = path;
422694edde99dc3782374977dab6d9aa34a16c13337Dake Gu        prepareMediaForPlaying();
4234702556bfd15c9819a7b2af759aee0f719cd631fsusnata        return true;
4244702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
4254702556bfd15c9819a7b2af759aee0f719cd631fsusnata
4264702556bfd15c9819a7b2af759aee0f719cd631fsusnata    private void prepareMediaForPlaying() {
4274702556bfd15c9819a7b2af759aee0f719cd631fsusnata        reset();
4284702556bfd15c9819a7b2af759aee0f719cd631fsusnata        try {
429aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata            if (mMediaSourceUri != null) {
430aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata                mPlayer.setDataSource(getContext(), mMediaSourceUri);
431aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata            } else if (mMediaSourcePath != null) {
432aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata                mPlayer.setDataSource(mMediaSourcePath);
433aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata            } else {
434aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata                return;
435aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata            }
4364702556bfd15c9819a7b2af759aee0f719cd631fsusnata        } catch (IOException e) {
4374702556bfd15c9819a7b2af759aee0f719cd631fsusnata            e.printStackTrace();
4384702556bfd15c9819a7b2af759aee0f719cd631fsusnata            throw new RuntimeException(e);
4394702556bfd15c9819a7b2af759aee0f719cd631fsusnata        }
4404702556bfd15c9819a7b2af759aee0f719cd631fsusnata        mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
4414702556bfd15c9819a7b2af759aee0f719cd631fsusnata        mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
4424702556bfd15c9819a7b2af759aee0f719cd631fsusnata            @Override
4434702556bfd15c9819a7b2af759aee0f719cd631fsusnata            public void onPrepared(MediaPlayer mp) {
4444702556bfd15c9819a7b2af759aee0f719cd631fsusnata                mInitialized = true;
4453bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                List<PlayerCallback> callbacks = getPlayerCallbacks();
4463bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                if (callbacks != null) {
4473bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    for (PlayerCallback callback: callbacks) {
4483bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                        callback.onPreparedStateChanged(MediaPlayerGlue.this);
4493bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    }
4504702556bfd15c9819a7b2af759aee0f719cd631fsusnata                }
4514702556bfd15c9819a7b2af759aee0f719cd631fsusnata            }
4524702556bfd15c9819a7b2af759aee0f719cd631fsusnata        });
4534702556bfd15c9819a7b2af759aee0f719cd631fsusnata
4544702556bfd15c9819a7b2af759aee0f719cd631fsusnata        if (mOnCompletionListener != null) {
4554702556bfd15c9819a7b2af759aee0f719cd631fsusnata            mPlayer.setOnCompletionListener(mOnCompletionListener);
4564702556bfd15c9819a7b2af759aee0f719cd631fsusnata        }
4574702556bfd15c9819a7b2af759aee0f719cd631fsusnata
4584702556bfd15c9819a7b2af759aee0f719cd631fsusnata        mPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
4594702556bfd15c9819a7b2af759aee0f719cd631fsusnata            @Override
4604702556bfd15c9819a7b2af759aee0f719cd631fsusnata            public void onBufferingUpdate(MediaPlayer mp, int percent) {
4613961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu                if (getControlsRow() == null) {
4623961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu                    return;
4633961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu                }
46495ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu                getControlsRow().setBufferedProgress((int) (mp.getDuration() * (percent / 100f)));
4654702556bfd15c9819a7b2af759aee0f719cd631fsusnata            }
4664702556bfd15c9819a7b2af759aee0f719cd631fsusnata        });
4674702556bfd15c9819a7b2af759aee0f719cd631fsusnata        mPlayer.prepareAsync();
4684702556bfd15c9819a7b2af759aee0f719cd631fsusnata        onStateChanged();
4694702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
4704702556bfd15c9819a7b2af759aee0f719cd631fsusnata
4714702556bfd15c9819a7b2af759aee0f719cd631fsusnata    /**
47295ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu     * This is a listener implementation for the {@link OnItemViewSelectedListener}.
47395ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu     * This implementation is required in order to detect KEY_DOWN events
474ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * on the {@link androidx.leanback.widget.PlaybackControlsRow.FastForwardAction} and
475ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * {@link androidx.leanback.widget.PlaybackControlsRow.RewindAction}. Thus you
4764702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * should <u>NOT</u> set another {@link OnItemViewSelectedListener} on your
47795ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu     * Fragment. Instead, override this method and call its super (this)
4784702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * implementation.
4794702556bfd15c9819a7b2af759aee0f719cd631fsusnata     *
4804702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * @see OnItemViewSelectedListener#onItemSelected(
4814702556bfd15c9819a7b2af759aee0f719cd631fsusnata     *Presenter.ViewHolder, Object, RowPresenter.ViewHolder, Object)
4824702556bfd15c9819a7b2af759aee0f719cd631fsusnata     */
4834702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
4844702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
4854702556bfd15c9819a7b2af759aee0f719cd631fsusnata                               RowPresenter.ViewHolder rowViewHolder, Row row) {
4864702556bfd15c9819a7b2af759aee0f719cd631fsusnata        if (item instanceof Action) {
4874702556bfd15c9819a7b2af759aee0f719cd631fsusnata            mSelectedAction = (Action) item;
4884702556bfd15c9819a7b2af759aee0f719cd631fsusnata        } else {
4894702556bfd15c9819a7b2af759aee0f719cd631fsusnata            mSelectedAction = null;
4904702556bfd15c9819a7b2af759aee0f719cd631fsusnata        }
4914702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
4924702556bfd15c9819a7b2af759aee0f719cd631fsusnata
4934702556bfd15c9819a7b2af759aee0f719cd631fsusnata    @Override
4943bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    public boolean isPrepared() {
4953bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        return mInitialized;
4963bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
4973bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu
4984702556bfd15c9819a7b2af759aee0f719cd631fsusnata    /**
49995ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu     * Implements {@link SurfaceHolder.Callback} that can then be set on the
50095ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu     * {@link PlaybackGlueHost}.
5014702556bfd15c9819a7b2af759aee0f719cd631fsusnata     */
50295ac470f2bbea06114a64906d95c0da7d9412db0Dake Gu    class VideoPlayerSurfaceHolderCallback implements SurfaceHolder.Callback {
5034702556bfd15c9819a7b2af759aee0f719cd631fsusnata        @Override
5044702556bfd15c9819a7b2af759aee0f719cd631fsusnata        public void surfaceCreated(SurfaceHolder surfaceHolder) {
5053961cea270f51c29433a7eb21ec5f8c9ca7bd7d7Dake Gu            setDisplay(surfaceHolder);
5064702556bfd15c9819a7b2af759aee0f719cd631fsusnata        }
5074702556bfd15c9819a7b2af759aee0f719cd631fsusnata
5084702556bfd15c9819a7b2af759aee0f719cd631fsusnata        @Override
5094702556bfd15c9819a7b2af759aee0f719cd631fsusnata        public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
5104702556bfd15c9819a7b2af759aee0f719cd631fsusnata        }
5114702556bfd15c9819a7b2af759aee0f719cd631fsusnata
5124702556bfd15c9819a7b2af759aee0f719cd631fsusnata        @Override
5134702556bfd15c9819a7b2af759aee0f719cd631fsusnata        public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
5144702556bfd15c9819a7b2af759aee0f719cd631fsusnata            setDisplay(null);
5154702556bfd15c9819a7b2af759aee0f719cd631fsusnata        }
5164702556bfd15c9819a7b2af759aee0f719cd631fsusnata    }
5174702556bfd15c9819a7b2af759aee0f719cd631fsusnata}
518