pct.droid.fragments.VideoPlayerFragment.java Source code

Java tutorial

Introduction

Here is the source code for pct.droid.fragments.VideoPlayerFragment.java

Source

/*
 * This file is part of Popcorn Time.
 *
 * Popcorn Time is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Popcorn Time is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Popcorn Time. If not, see <http://www.gnu.org/licenses/>.
 */

package pct.droid.fragments;

import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.StateListDrawable;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;

import com.github.sv244.torrentstream.StreamStatus;
import com.github.sv244.torrentstream.Torrent;

import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import pct.droid.R;
import pct.droid.activities.BeamPlayerActivity;
import pct.droid.base.content.preferences.Prefs;
import pct.droid.base.fragments.BaseVideoPlayerFragment;
import pct.droid.base.subs.Caption;
import pct.droid.base.utils.AnimUtils;
import pct.droid.base.utils.FragmentUtil;
import pct.droid.base.utils.LocaleUtils;
import pct.droid.base.utils.PixelUtils;
import pct.droid.base.utils.PrefUtils;
import pct.droid.base.utils.StringUtils;
import pct.droid.base.utils.VersionUtils;
import pct.droid.widget.StrokedRobotoTextView;

public class VideoPlayerFragment extends BaseVideoPlayerFragment
        implements View.OnSystemUiVisibilityChangeListener {

    @Bind(R.id.toolbar)
    Toolbar mToolbar;
    @Bind(R.id.progress_indicator)
    ProgressBar mProgressIndicator;
    @Bind(R.id.video_surface)
    SurfaceView videoSurface;
    @Bind(R.id.subtitle_text)
    StrokedRobotoTextView mSubtitleText;
    @Bind(R.id.control_layout)
    RelativeLayout mControlLayout;
    @Bind(R.id.player_info)
    TextView mPlayerInfo;
    @Bind(R.id.control_bar)
    pct.droid.widget.SeekBar mControlBar;
    @Bind(R.id.play_button)
    ImageButton mPlayButton;
    @Bind(R.id.forward_button)
    ImageButton mForwardButton;
    @Bind(R.id.rewind_button)
    ImageButton mRewindButton;
    @Bind(R.id.subs_button)
    ImageButton mSubsButton;
    @Bind(R.id.current_time)
    TextView mCurrentTimeTextView;
    @Bind(R.id.length_time)
    TextView lengthTime;
    View mDecorView;

    private AudioManager mAudioManager;

    private long mLastSystemShowTime = System.currentTimeMillis();

    private static final int FADE_OUT_OVERLAY = 5000;
    private static final int FADE_OUT_INFO = 1000;

    private int mLastSystemUIVisibility;
    private boolean mOverlayVisible = true;

    private Handler mDisplayHandler;

    private static final int TOUCH_NONE = 0;
    private static final int TOUCH_VOLUME = 1;
    private static final int TOUCH_BRIGHTNESS = 2;
    private static final int TOUCH_SEEK = 3;
    private int mTouchAction;
    private int mSurfaceYDisplayRange;
    private float mTouchY, mTouchX;

    private int mAudioMax;
    private float mVol;

    private boolean mIsFirstBrightnessGesture = true;
    private float mRestoreAutoBrightness = -1f;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mShowReload = true;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_videoplayer, container, false);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        view.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return onTouchEvent(event);
            }
        });
        ButterKnife.bind(this, view);

        if (LocaleUtils.isRTL(LocaleUtils.getCurrent())) {
            Drawable forward = mForwardButton.getDrawable();
            Drawable rewind = mRewindButton.getDrawable();
            mRewindButton.setImageDrawable(forward);
            mForwardButton.setImageDrawable(rewind);
        }

        int color = getResources().getColor(R.color.primary);
        LayerDrawable progressDrawable;
        if (!VersionUtils.isLollipop()) {
            progressDrawable = (LayerDrawable) getResources().getDrawable(R.drawable.scrubber_progress_horizontal);
        } else {
            if (mControlBar.getProgressDrawable() instanceof StateListDrawable) {
                StateListDrawable stateListDrawable = (StateListDrawable) mControlBar.getProgressDrawable();
                progressDrawable = (LayerDrawable) stateListDrawable.getCurrent();
            } else {
                progressDrawable = (LayerDrawable) mControlBar.getProgressDrawable();
            }
        }
        progressDrawable.findDrawableByLayerId(android.R.id.progress).setColorFilter(color, PorterDuff.Mode.SRC_IN);
        progressDrawable.findDrawableByLayerId(android.R.id.secondaryProgress).setColorFilter(color,
                PorterDuff.Mode.SRC_IN);

        mControlBar.setProgressDrawable(progressDrawable);
        mControlBar.getThumbDrawable().setColorFilter(color, PorterDuff.Mode.SRC_IN);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        setRetainInstance(true);

        getAppCompatActivity().setSupportActionBar(mToolbar);

        videoSurface.setVisibility(View.VISIBLE);

        mToolbar.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                onTouchEvent(event);
                return true;
            }
        });

        /* Services and miscellaneous */
        mAudioManager = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
        mAudioMax = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);

        mDisplayHandler = new Handler(Looper.getMainLooper());

        mDecorView = getActivity().getWindow().getDecorView();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            mDecorView.setOnSystemUiVisibilityChangeListener(this);
        }

        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
            getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            mToolbar.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
                    getResources().getDimensionPixelSize(R.dimen.abc_action_bar_default_height_material)
                            + PixelUtils.getStatusBarHeight(getActivity())));
            mToolbar.setPadding(mToolbar.getPaddingLeft(), PixelUtils.getStatusBarHeight(getActivity()),
                    mToolbar.getPaddingRight(), mToolbar.getPaddingBottom());
        }

        if (getAppCompatActivity().getSupportActionBar() != null) {
            if (null != mCallback.getInfo()) {
                if (mMedia != null && mMedia.title != null) {
                    if (null != mCallback.getInfo().getQuality()) {
                        getAppCompatActivity().getSupportActionBar().setTitle(getString(R.string.now_playing) + ": "
                                + mMedia.title + " (" + mCallback.getInfo().getQuality() + ")");
                    } else {
                        getAppCompatActivity().getSupportActionBar()
                                .setTitle(getString(R.string.now_playing) + ": " + mMedia.title);
                    }
                } else {
                    getAppCompatActivity().getSupportActionBar().setTitle(getString(R.string.now_playing));
                }
            } else {
                getAppCompatActivity().getSupportActionBar().setTitle(getString(R.string.now_playing));
            }
            getAppCompatActivity().getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        }

        mSubtitleText.setTextColor(PrefUtils.get(getActivity(), Prefs.SUBTITLE_COLOR, Color.WHITE));
        mSubtitleText.setTextSize(TypedValue.COMPLEX_UNIT_DIP,
                PrefUtils.get(getActivity(), Prefs.SUBTITLE_SIZE, 16));
        mSubtitleText.setStrokeColor(PrefUtils.get(getActivity(), Prefs.SUBTITLE_STROKE_COLOR, Color.BLACK));
        mSubtitleText.setStrokeWidth(TypedValue.COMPLEX_UNIT_DIP,
                PrefUtils.get(getActivity(), Prefs.SUBTITLE_STROKE_WIDTH, 2));

        mControlBar.setOnSeekBarChangeListener(mOnControlBarListener);

        getAppCompatActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC);
    }

    @Override
    public void onPlaybackEndReached() {
        getVideoSurface().setKeepScreenOn(false);
        //todod:
    }

    @Override
    public void onStop() {
        super.onStop();
        //restore brightness
        if (mRestoreAutoBrightness != -1f) {
            int brightness = (int) (mRestoreAutoBrightness * 255f);
            Settings.System.putInt(getActivity().getContentResolver(), Settings.System.SCREEN_BRIGHTNESS,
                    brightness);
            Settings.System.putInt(getActivity().getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE,
                    Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mAudioManager = null;
    }

    private AppCompatActivity getAppCompatActivity() {
        return (AppCompatActivity) getActivity();
    }

    @Override
    protected SurfaceView getVideoSurface() {
        return videoSurface;
    }

    public boolean onTouchEvent(MotionEvent event) {
        DisplayMetrics screen = new DisplayMetrics();
        getAppCompatActivity().getWindowManager().getDefaultDisplay().getMetrics(screen);

        if (mSurfaceYDisplayRange == 0) {
            mSurfaceYDisplayRange = Math.min(screen.widthPixels, screen.heightPixels);
        }

        float y_changed = event.getRawY() - mTouchY;
        float x_changed = event.getRawX() - mTouchX;

        // coef is the gradient's move to determine a neutral zone
        float coef = Math.abs(y_changed / x_changed);
        float xgesturesize = ((x_changed / screen.xdpi) * 2.54f);

        int[] offset = new int[2];
        videoSurface.getLocationOnScreen(offset);

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            // Audio
            mTouchY = event.getRawY();
            mVol = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
            mTouchAction = TOUCH_NONE;
            // Seek
            mTouchX = event.getRawX();
            break;

        case MotionEvent.ACTION_MOVE:
            if (coef > 2) {
                mTouchY = event.getRawY();
                mTouchX = event.getRawX();
                if ((int) mTouchX > (screen.widthPixels / 2)) {
                    doVolumeTouch(y_changed);
                }
                if ((int) mTouchX < (screen.widthPixels / 2)) {
                    if (Settings.System.canWrite(getContext())) {
                        doVolumeTouch(y_changed);
                    } else {
                        doBrightnessTouch(y_changed);
                    }
                }
            } else {
                // Seek (Right or Left move)
                doSeekTouch(coef, xgesturesize, false);
            }
            break;

        case MotionEvent.ACTION_UP:
            if (mTouchAction == TOUCH_NONE) {
                if (!mOverlayVisible) {
                    showOverlay();
                } else {
                    hideOverlay();
                }
            } else {
                showOverlay();
            }

            doSeekTouch(coef, xgesturesize, true);
            break;
        }
        return true;
    }

    @Override
    public void onSystemUiVisibilityChange(int visibility) {
        if ((mLastSystemUIVisibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
                && (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
            showOverlay();
        }

        mLastSystemUIVisibility = visibility;
    }

    private void doSeekTouch(float coef, float gesturesize, boolean seek) {
        // No seek action if coef > 0.5 and gesturesize < 1cm
        if (coef > 0.5 || Math.abs(gesturesize) < 1) {
            return;
        }

        if (mTouchAction != TOUCH_NONE && mTouchAction != TOUCH_SEEK) {
            return;
        }
        mTouchAction = TOUCH_SEEK;

        // Size of the jump, 10 minutes max (600000), with a bi-cubic progression, for a 8cm gesture
        int jump = (int) (Math.signum(gesturesize) * ((600000 * Math.pow((gesturesize / 8), 4)) + 3000));

        // Adjust the jump
        if ((jump > 0) && ((getCurrentTime() + jump) > mControlBar.getSecondaryProgress())) {
            jump = (int) (mControlBar.getSecondaryProgress() - getCurrentTime());
        }
        if ((jump < 0) && ((getCurrentTime() + jump) < 0)) {
            jump = (int) -getCurrentTime();
        }

        long currentTime = getCurrentTime();
        if (seek && mControlBar.getSecondaryProgress() > 0) {
            seek(jump);
        }

        if (getDuration() > 0) {
            showPlayerInfo(String.format("%s%s (%s)", jump >= 0 ? "+" : "", StringUtils.millisToString(jump),
                    StringUtils.millisToString(currentTime + jump)));
        }
    }

    private void doVolumeTouch(float y_changed) {
        if (mTouchAction != TOUCH_NONE && mTouchAction != TOUCH_VOLUME)
            return;
        float delta = -((y_changed / mSurfaceYDisplayRange) * mAudioMax);
        mVol += delta;
        int vol = (int) Math.min(Math.max(mVol, 0), mAudioMax);
        if (delta != 0f) {
            setAudioVolume(vol);
        }
    }

    private void setAudioVolume(int vol) {
        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, vol, 0);

        /* Since android 4.3, the safe volume warning dialog is displayed only with the FLAG_SHOW_UI flag.
         * We don't want to always show the default UI volume, so show it only when volume is not set. */
        int newVol = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
        if (vol != newVol)
            mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, vol, AudioManager.FLAG_SHOW_UI);

        mTouchAction = TOUCH_VOLUME;
        showPlayerInfo(getString(R.string.volume) + '\u00A0' + Integer.toString(vol));
    }

    private void initBrightnessTouch() {
        float brightnesstemp = 0.6f;
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO && Settings.System.getInt(
                    getActivity().getContentResolver(),
                    Settings.System.SCREEN_BRIGHTNESS_MODE) == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
                Settings.System.putInt(getActivity().getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE,
                        Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
                mRestoreAutoBrightness = android.provider.Settings.System.getInt(getActivity().getContentResolver(),
                        android.provider.Settings.System.SCREEN_BRIGHTNESS) / 255.0f;
            } else {
                brightnesstemp = android.provider.Settings.System.getInt(getActivity().getContentResolver(),
                        android.provider.Settings.System.SCREEN_BRIGHTNESS) / 255.0f;
            }
        } catch (Settings.SettingNotFoundException e) {
            e.printStackTrace();
        }
        WindowManager.LayoutParams lp = getAppCompatActivity().getWindow().getAttributes();
        lp.screenBrightness = brightnesstemp;
        getAppCompatActivity().getWindow().setAttributes(lp);
        mIsFirstBrightnessGesture = false;
    }

    private void doBrightnessTouch(float y_changed) {
        if (mTouchAction != TOUCH_NONE && mTouchAction != TOUCH_BRIGHTNESS)
            return;
        if (mIsFirstBrightnessGesture)
            initBrightnessTouch();
        mTouchAction = TOUCH_BRIGHTNESS;

        // Set delta : 2f is arbitrary for now, it possibly will change in the future
        float delta = -y_changed / mSurfaceYDisplayRange;

        changeBrightness(delta);
    }

    private void changeBrightness(float delta) {
        // Estimate and adjust Brightness
        WindowManager.LayoutParams lp = getAppCompatActivity().getWindow().getAttributes();
        lp.screenBrightness = Math.min(Math.max(lp.screenBrightness + delta, 0.01f), 1);
        // Set Brightness
        getAppCompatActivity().getWindow().setAttributes(lp);
        showPlayerInfo(getString(R.string.brightness) + '\u00A0' + Math.round(lp.screenBrightness * 15));
    }

    @Override
    protected void onErrorEncountered() {
        /* Encountered Error, exit player with a message */
        AlertDialog dialog = new AlertDialog.Builder(getActivity())
                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int id) {
                        getAppCompatActivity().finish();
                    }
                }).setTitle(R.string.encountered_error_title).setMessage(R.string.encountered_error).create();
        dialog.show();
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    public void showOverlay() {
        if (!mOverlayVisible) {
            updatePlayPauseState();

            AnimUtils.fadeIn(mControlLayout);
            AnimUtils.fadeIn(mToolbar);

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
                mDecorView.setSystemUiVisibility(uiOptions);
            } else {
                getAppCompatActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
                getAppCompatActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
            }

            mLastSystemShowTime = System.currentTimeMillis();
        }

        mOverlayVisible = true;
        mDisplayHandler.removeCallbacks(mOverlayHideRunnable);
        mDisplayHandler.postDelayed(mOverlayHideRunnable, FADE_OUT_OVERLAY);
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    public void hideOverlay() {
        // Can only hide 1000 millisec after show, because navbar doesn't seem to hide otherwise.
        if (mLastSystemShowTime + 1000 < System.currentTimeMillis()) {
            AnimUtils.fadeOut(mControlLayout);
            AnimUtils.fadeOut(mToolbar);

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
                mDecorView.setSystemUiVisibility(uiOptions);
            } else {
                getAppCompatActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
                getAppCompatActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
            }

            mDisplayHandler.removeCallbacks(mOverlayHideRunnable);
            mOverlayVisible = false;
        }
    }

    protected void showPlayerInfo(String text) {
        mPlayerInfo.setVisibility(View.VISIBLE);
        mPlayerInfo.setText(text);
        mDisplayHandler.removeCallbacks(mInfoHideRunnable);
        mDisplayHandler.postDelayed(mInfoHideRunnable, FADE_OUT_INFO);
    }

    private void hidePlayerInfo() {
        if (mPlayerInfo.getVisibility() == View.VISIBLE) {
            Animation fadeOutAnim = AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out);
            mPlayerInfo.startAnimation(fadeOutAnim);
        }
        mPlayerInfo.setVisibility(View.INVISIBLE);
    }

    public void updatePlayPauseState() {
        if (!FragmentUtil.isAdded(this))
            return;

        if (isPlaying()) {
            mPlayButton.setImageResource(R.drawable.ic_av_pause);
            mPlayButton.setContentDescription(getString(R.string.pause));
        } else {
            mPlayButton.setImageResource(R.drawable.ic_av_play);
            mPlayButton.setContentDescription(getString(R.string.play));
        }
    }

    private SeekBar.OnSeekBarChangeListener mOnControlBarListener = new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
            setSeeking(true);
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            setSeeking(false);
        }

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            if (fromUser && isSeeking() && progress <= (getDuration() / 100 * seekBar.getSecondaryProgress())) {
                setLastSubtitleCaption(null);
                setCurrentTime(progress);
                VideoPlayerFragment.this.onProgressChanged(getCurrentTime(), getDuration());
                progressSubtitleCaption();
            }
        }
    };

    @Override
    protected void onHardwareAccelerationError() {
        AlertDialog dialog = new AlertDialog.Builder(getActivity())
                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int id) {
                        disableHardwareAcceleration();
                        loadMedia();
                    }
                }).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int id) {
                        getAppCompatActivity().finish();
                    }
                }).setTitle(R.string.hardware_acceleration_error_title)
                .setMessage(R.string.hardware_acceleration_error_message).create();
        if (!getAppCompatActivity().isFinishing())
            dialog.show();
    }

    private Runnable mOverlayHideRunnable = new Runnable() {
        @Override
        public void run() {
            hideOverlay();
        }
    };

    private Runnable mInfoHideRunnable = new Runnable() {
        @Override
        public void run() {
            hidePlayerInfo();
        }
    };

    @Override
    protected void showTimedCaptionText(final Caption text) {
        mDisplayHandler.post(new Runnable() {
            @Override
            public void run() {
                if (text == null) {
                    if (mSubtitleText.getText().length() > 0) {
                        mSubtitleText.setText("");
                    }
                    return;
                }
                SpannableStringBuilder styledString = (SpannableStringBuilder) Html.fromHtml(text.content);

                ForegroundColorSpan[] toRemoveSpans = styledString.getSpans(0, styledString.length(),
                        ForegroundColorSpan.class);
                for (ForegroundColorSpan remove : toRemoveSpans) {
                    styledString.removeSpan(remove);
                }

                if (!mSubtitleText.getText().toString().equals(styledString.toString())) {
                    mSubtitleText.setText(styledString);
                }
            }
        });
    }

    @Override
    protected void setProgressVisible(boolean visible) {
        if (mProgressIndicator.getVisibility() == View.VISIBLE && visible)
            return;

        if (mProgressIndicator.getVisibility() == View.GONE && !visible)
            return;

        mProgressIndicator.setVisibility(visible ? View.VISIBLE : View.GONE);
    }

    /**
     * Updates the overlay when the media playback progress has changed
     *
     * @param currentTime Current progress time
     * @param duration Duration of full medias
     */
    @Override
    protected void onProgressChanged(long currentTime, long duration) {
        mControlBar.setMax((int) duration);
        mControlBar.setProgress((int) currentTime);
        mControlBar.setSecondaryProgress(0); // hack to make the secondary progress appear on Android 5.0
        mControlBar.setSecondaryProgress(getStreamerProgress());

        if (getCurrentTime() >= 0)
            mCurrentTimeTextView.setText(StringUtils.millisToString(currentTime));
        if (getDuration() >= 0)
            lengthTime.setText(StringUtils.millisToString(duration));
    }

    @Override
    public void onStreamProgress(Torrent torrent, StreamStatus streamStatus) {
        super.onStreamProgress(torrent, streamStatus);
        mControlBar.setSecondaryProgress(getStreamerProgress());
    }

    public void enableSubsButton(boolean b) {
        mSubsButton.setVisibility(b ? View.VISIBLE : View.INVISIBLE);
    }

    protected void updateSubtitleSize(int size) {
        mSubtitleText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, size);
    }

    @OnClick(R.id.play_button)
    void onPlayPauseClick() {
        togglePlayPause();
    }

    @OnClick(R.id.rewind_button)
    void onRewindClick() {
        seekBackwardClick();
    }

    @OnClick(R.id.forward_button)
    void onForwardClick() {
        seekForwardClick();
    }

    @OnClick(R.id.scale_button)
    void onScaleClick() {
        scaleClick();
    }

    @OnClick(R.id.subs_button)
    void onSubsClick() {
        subsClick();
    }

    public void startBeamPlayerActivity() {
        BeamPlayerActivity.startActivity(getActivity(), mCallback.getInfo(), getCurrentTime());
    }

}